c# - "too much"什么时候异步等待?所有方法都应该返回 Task 吗?

标签 c# asp.net .net asynchronous async-await

<分区>

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

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

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

我的非异步方法应该是异步的吗?我是不是考虑了太多的同步编程方式而遗漏了什么?

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;
}

最佳答案

所有异步”背后的理念是促进 non-blocking I/O .

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

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

// 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您不需要提供异步实现:

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);
}

我的观点是...

  • ...实现返回任务并使用 Async 的所有内容方法标识符末尾的后缀( WhateverAsyncWhoKnowsAsyncDoStuffAsync ...)...

  • ...除非您可以确定整个方法将始终执行非常简单的事情,这些事情不会长时间阻塞应用程序/服务的线程(很长的时间可以是几毫秒,现在想象一下代码每当调用某些方法时,它不会阻塞主应用程序线程 100 毫秒,并且您的代码可以在 等待 100 毫秒时优先执行某些内容....)。我会在这里包括字符串操作、简单的算术运算、配置方法......

如果您的代码现在不是异步的,您可以将它变成实际的异步操作而不影响整个代码库,因为您只需要更改 Task.FromResult<T>(T result)调用实际返回一个未完成的 Task实例。

归根结底,您的方法具有异步签名,并且对它们的依赖并不关心它们是否实际上是异步的,并且这些方法实现决定什么是异步或同步,而不是将此责任交给来电者。

关于c# - "too much"什么时候异步等待?所有方法都应该返回 Task 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30661416/

相关文章:

c# - 当 GridView 为空时隐藏面板

c# - 非常奇怪 - 当我使用断点时,代码(随机)的工作方式不同

c# - 用于C#的构建工具,类似于Java的maven/gradle

c# - WPF Listview 空文本

c# - 在更改新的随机速度之前如何等待秒数?

c# - cmd.ExecuteNonQuery() 在我的程序中到底做了什么

c# - 在运行时更改成员身份提供程序 ApplicationName。如何?

c# - 日期采用 MM/dd/yyyy 格式,这在服务器上是错误的

javascript - 从页面中删除所有 JavaScript

.net - 限制 WebClient DownloadFile 最大文件大小