簡體   English   中英

我應該將任務包裝在另一個任務中還是應該返回創建的任務?

[英]Should I wrap a task in another task or should I just return the created task?

我正在構建一個使用 ADO.NET 的 .NET 4.0 應用程序,所以我不能使用 async/await。 我不想要一個解決方案,但我確實想知道以下哪些實現是最好的以及為什么。 我的單元測試通過了所有三個實現,但我想知道這三個之間的區別。

#1 嵌套任務

在我的第一個實現中,我將一個任務包裝在另一個任務中。 我認為旋轉兩個任務對性能不利,但我不確定。

public virtual Task<IDataReader> ExecuteReaderAsync(IDbCommand dbCommand, CancellationToken cancellationToken)
{
    return Task.Factory.StartNew(() =>
    {
        var sqlCommand = CheckIfSqlCommand(dbCommand);
        PrepareExecuteReader(dbCommand);

        return Task<IDataReader>
            .Factory
            .FromAsync(sqlCommand.BeginExecuteReader, sqlCommand.EndExecuteReader, null)
            .Result;
    }, cancellationToken);
}

#2 使用 TaskCompletionSource

然后我嘗試將結果包裝在TaskCompletionSource因此我只有一項任務。

public virtual Task<IDataReader> ExecuteReaderAsync(IDbCommand dbCommand, CancellationToken cancellationToken)
{
    var taskCompletionSource = new TaskCompletionSource<IDataReader>();
    var sqlCommand = CheckIfSqlCommand(dbCommand);
    PrepareExecuteReader(dbCommand);

    var reader = Task<IDataReader>
        .Factory
        .FromAsync(sqlCommand.BeginExecuteReader, sqlCommand.EndExecuteReader, null)
        .Result;

    taskCompletionSource.SetResult(reader);

    return taskCompletionSource.Task;
}

#3 直接返回Task

我的最終解決方案是直接返回我創建的任務而不是包裝它。

public virtual Task<IDataReader> ExecuteReaderAsync(IDbCommand dbCommand, CancellationToken cancellationToken)
{
    var sqlCommand = CheckIfSqlCommand(dbCommand);
    PrepareExecuteReader(dbCommand);

    return Task<IDataReader>
        .Factory
        .FromAsync(sqlCommand.BeginExecuteReader, sqlCommand.EndExecuteReader, null);
}

所以基本上我的問題是:

我應該使用什么選項或者有更好的方法來做到這一點?

你的#3 是最好的。 前兩個無緣無故地引入了復雜性。

1 可能會添加另一個線程,純粹是為了異步運行CheckIfSqlCommand()PrepareExecuteReader() 這可能是您想要的,但它們聽起來不像需要很長時間的命令。

2 引用.Result任務,它會阻塞直到任務完成,因此違背了使用任務的全部目的。

我們在Tasks使用異步編程有兩種場景,一種是海量計算,一種是I/O
在大規模計算的情況下,我們總是使用Task.Run從線程池中請求一個線程以避免阻塞線程。
I/O情況下,如果沒有提供async api,我們總是使用TaskCompletionSourceTask.Factory.FromAsync來構建一個async方法。 我認為混合這兩個不是一個好的解決方案。
順便說一句, Task.Run總是在客戶端應用程序中使用,由於並發請求,服務器端一般不使用Task.Run
這是一個很好的帖子,您可以參考:
https://docs.microsoft.com/en-us/archive/msdn-magazine/2010/september/async-tasks-simplify-asynchronous-programming-with-tasks

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM