Task.ContinueWith混乱

n8w*_*wrl 5 asynchronous task async-await .net-4.5

使用ASP.NET 4.5我正在尝试使用新的async/await玩具.我有一个IDataReader实现类,它包含特定于供应商的读者(如SqlDatareader).我有一个简单的ExecuteSql()方法,它同步操作,如下所示:

public IDataReader ReaderForSql(string sql)
{
    var cmd = NewCommand(sql, CommandType.Text);
    return DBReader.ReaderFactory(cmd.ExecuteReader());
}
Run Code Online (Sandbox Code Playgroud)

我想要的是这个的异步版本.这是我的第一次尝试:

public Task<IDataReader> ReaderForSqlAsync(string sql, CancellationToken ct)
{
    var cmd = NewCommand(sql, CommandType.Text);
    return cmd.ExecuteReaderAsync(ct)
              .ContinueWith(t => DBReader.ReaderFactory(t.Result));
}
Run Code Online (Sandbox Code Playgroud)

我用它:

using (var r = await connection.ReaderForSqlAsync("SELECT ...", cancellationToken))
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,这在我的有限测试中效果很好.但是看了几次这个Cloud9视频之后:http://channel9.msdn.com/Events/aspConf/aspConf/Async-in-ASP-NET我对他们提出的关于以下问题的警告感到不安:

  • 继续消耗额外的线程池资源 - Readerfactory非常轻松!
  • Task.Result阻塞

因为我将ContinuationToken传递给ExecuteReaderAsync(),所以似乎取消只是ExecuteReaderAsync()失败的另一个原因(毕竟它是SQL!)

当我尝试继续使用它时,任务的状态是什么?t.Result会阻止吗?扔?做错了什么?

Ste*_*ary 5

ContinueWith默认情况下将使用当前任务调度程序(线程池线程),但您可以通过传递TaskContinuationOptions.ExecuteSynchronously和显式TaskScheduler.

也就是说,我会将其作为第一次尝试:

public async Task<IDataReader> ReaderForSqlAsync(string sql, CancellationToken ct)
{
  var cmd = NewCommand(sql, CommandType.Text);
  var readerResult = await cmd.ExecuteReaderAsync(ct).ConfigureAwait(false);
  return DBReader.ReaderFactory(readerResult);
}
Run Code Online (Sandbox Code Playgroud)

async并以一致的方式为您await处理所有ContinueWith美食和边缘条件。如果性能测试表明这是一个严重的问题,则可能会将此代码复杂化以使其更快。