4

たとえば、以下のシグネチャを持つメソッドを書いているとしましょう (C#4 なので async キーワードはありません):

public Task Refresh();  

1 つのメソッド ( も返すTask) を呼び出して通信作業を実行し、タスクの継続を実行して、取得したデータに基づいて内部状態を更新します。例えば:

public Task Refresh()
{
    Task<MyData> commsTask = datasource.LoadData();
    Task handleDataTask = commsTask.ContinueWith( HandleNewData );

    return ?;
}  

完了状態を返すhandleDataTaskと、「更新」操作の結果が正しく追跡されますが、開始状態が正しく報告されません。

両方を新しいものにラップTask.Factory.StartNewして子タスクとして作成することはできますが、一部のタスクの継続をリンクするためだけに新しいスレッドをスプールするのは無駄に思えます。

確かにTPLでこれを行う効率的な方法はありますか?

4

2 に答える 2

3

通常、最終状態Task.Statusを調べるためにのみ使用されます。その状態はいつでも変わる可能性があるため、とにかくタスクが実行されていることに依存することはできません。Started

そのため、返されたタスクが完了するまで「奇妙な」状態であっても問題ありません。3 つの完了状態 ( CompletedCanceledFaulted) のみが重要です。

于 2012-04-15T12:00:38.937 に答える
0

さらに調査を行ったところ、同様の SO の質問といくつかのブログ投稿が見つかりました。

TaskCompletionSource なしのタスク チェーン?

http://blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx

http://msmvps.com/blogs/jon_skeet/archive/2011/05/20/eduasync-part-7-generated-code-from-a-simple-async-method.aspx

したがって、半分の答えがあります。新しいスレッドをスプールして子タスクとしてアタッチすることなく、すべての子タスクを表す Task インスタンスを作成できます。単純に TaskCompletionSource を使用します。以下の簡単な例を、失敗やキャンセルの処理なしで上記の私の質問に適用します。

public Task Refresh()
{
    var refreshTaskSource = new TaskCompletionSource<object>();

    Task<MyData> commsTask = datasource.LoadData();
    Task handleDataTask = commsTask.ContinueWith( HandleNewData );
    handleDataTask.ContinueWith( t => refreshTaskSource.SetResult(null) );

    return refreshTaskSource.Task;
} 

ただし、このメソッドによって返される Task は、(または、これらのシナリオを処理していない場合は、Faulted/Cancelled)TaskStatus.WaitingForActivationから直接遷移するようになりました。TaskStatus.RanToCompletion

于 2012-04-16T10:48:23.920 に答える