什么时候“太多"?异步等待?所有方法都应返回Task吗? [英] When is "too much" async and await? Should all methods return Task?

查看:62
本文介绍了什么时候“太多"?异步等待?所有方法都应返回Task吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个项目,并使用异步和等待方法.所有人都说异步应用程序是从头开始构建的,那么您真的应该有任何同步方法吗?所有方法都应该返回Task以便可以异步使用吗?

I am building a project and using async and await methods. Everyone says that async application are built from the ground up, so should you really have any sync methods? Should all methods you return a Task so you can use the asynchronously?

让我们举一个简单的例子,其中我使用Sql将数据加载到集合中,下面是一些代码.

Lets take a simple example, where by i am using Sql to load data into a collection, here is some code.

此代码使用ExecuteQueryAsync方法从表中加载数据,方法GetQuery构造SQL,但调用GetTableColumns.一旦生成并执行了SQL,我便会遍历集合并通过调用GetDataFromReader填充每个对象.

This code loads data from a table using ExecuteQueryAsync method, the method GetQuery constructs the SQL, but calling GetTableColumns. Once the SQL is generated and executed, i loop through the collection and populate each object by calling GetDataFromReader.

我的非异步方法应该异步吗?我是否在想太多的编程同步方式并缺少某些东西?

Should my non async methods, be async? Am i thinking in too much of a sync-way of programming and missing something?

public async Task<ICollection<MyObject>> ExecuteQueryAsync(Module module, List<SqlParameter> parameters)
{
    var result = new Collection<MyObject>();
    var query = GetQuery(module);

    using (var conn = new SqlConnection(_context.Database.Connection.ConnectionString))
    {
        await conn.OpenAsync();

        using (var cmd = new SqlCommand(query, conn))
        {
            if (parameters != null)
                cmd.Parameters.AddRange(parameters.ToArray());

            using (var dr = await cmd.ExecuteReaderAsync())
            {
                while (await dr.ReadAsync())
                {
                    result.Add(GetDataFromReader(module, dr));
                }

            }
        }

    }

    return result;
}

public string GetQuery(Module module)
{
    return "SELECT " + string.Join(",", GetTableColumns(module).ToArray()) + " FROM [TableA] ";
}

public List<string> GetTableColumns(Module module) 
{
    var columnNames = new List<string>();

    // get all list fields for the module
    var fields = (from a in module.Groups.SelectMany(a => a.Fields) select a).ToList();

    foreach (var field in fields)
    {
        if (field.Type == FieldType.List) {
            string query = "STUFF(";
            query += "(SELECT ';' + [Value] FROM [TableB] FOR XML PATH(''))";
            query += ", 1, 1, '') AS [" + field.ColumnName + "]";

            columnNames.Add(query);
        } else {
            columnNames.Add("[" + field.ColumnName + "]");
        }
    }

    return columnNames;
}

public MyObject GetDataFromReader(Module module, IDataReader dataReader)
{
    var entity = new MyObject();

    for (var i = 0; i < dataReader.FieldCount; i++)
    {
        object value = null;
        var fieldName = dataReader.GetName(i);

        if (!dataReader.IsDBNull(i))
        {
            value = dataReader.GetValue(i);
        }

        entity[fieldName] = value;
    }

    return entity;
}

推荐答案

"所有异步"背后的理念是促进

The philosophy behind "all async" is to facilitate non-blocking I/O.

也就是说,您的主要异步代码可以使环境优先考虑应用程序或服务的执行方式,并在多线程,多进程系统中实现尽可能多的并行执行.

That is, your primarily async code can potentially let the environment prioritize how your application or service is being executed and achieve as much parallelized execution as possible in a multi-threaded, multi-process system.

例如,ASP.NET Web API,ASP.NET MVC甚至ASP.NET Web窗体(代码隐藏)可以利用所有异步的优势继续为其他用户处理Web请求一些异步操作正在执行.因此,即使像IIS或Katana这样的Web服务器可能会限制并发请求的数量,异步操作也会在与请求线程不同的线程中执行,这允许Web服务器在异步操作获得结果的同时响应其他请求.他们需要继续:

For example, ASP.NET Web API, ASP.NET MVC or even ASP.NET Web Forms (code-behind) can take advantage of all async to continue attending Web requests to other users while some async operation is being executed. Thus, even when a Web server like IIS or Katana might limit the number of concurrent requests, async operations are executed in a separate thread from the request thread, and this is allows the Web server to respond to other requests while async operations get a result and they need to continue:

// While WhateverAsync is being executed, current thread can be used 
// by a new request and so on.
// Obviously, this will work this way if WhateverAsync actually
// does its work in another thread...
await WhateverAsync();

那么...您是否需要异步实现所有内容?即使返回Task,您也无需提供异步实现:

So... do you need to implement everything asynchronously? Even when you return a Task you don't need to provide an asynchronous implementation:

public Task WhateverAsync()
{
    // This creates a fake Task object which 
    // simulates a Task that has already ended successfully
    // and without creating a child thread!
    // This, this method is a SYNCHRONOUS implementation unless
    // the whole method doesn't execute asynchronous operations.
    return Task.FromResult(true);
}

我的观点是...

  • ...实现所有返回Task的方法,并在方法标识符(WhateverAsyncWhoKnowsAsyncDoStuffAsync ...)末尾使用Async后缀...

  • ...implement everything returning a Task and using the Async suffix at the end of method's identifiers (WhateverAsync, WhoKnowsAsync, DoStuffAsync...)...

...除非您可以确定整个方法将始终执行非常简单的操作,否则它们很长时间都不会阻塞应用程序/服务的线程(长时间可能是几毫秒,现在想象一下代码每当调用某些方法时,它就不会在100毫秒内阻塞主应用程序线程,并且您的代码可以在唤醒 100毫秒时优先执行某些操作……).我将在此处包括字符串操作,简单的算术运算,配置方法...

...unless you can be sure that the whole method will always execute a very simple things which can't block application/service's thread for a long time (long time can be few miliseconds, now imagine a code which doesn't block main app thread for 100ms whenever some method is called and your code can prioritize executing something while it awaits 100ms....). I would include here string manipulation, simple arithmetic operations, configuration methods...

如果今天的代码不是异步的,则可以将其转换为实际的异步操作,而不会影响整个代码库,因为您只需更改Task.FromResult<T>(T result)调用即可实际返回未完成的Task实例.

If your code isn't async today, you can turn it into actual async operations without affecting the entire code base, as you only need to change Task.FromResult<T>(T result) calls to actually return an unfinished Task instance.

最终,您的方法具有异步签名,并且对它们的依赖关系不在乎它们是否实际上是异步的,并且这些方法的实现决定了异步或同步是什么,而不是将责任分配给呼叫者..

这篇关于什么时候“太多"?异步等待?所有方法都应返回Task吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆