0

async/await次の方法で、同時に TPL とうまく連携する実行コンテキストを探しています (予想される動作)。

async Task<string> ReadContext(string slot)
{
    // Perform some async code
    ...
    return Context.Read(slot);
}

(1)仲良く遊ぶasync/await

Context.Store("slot", "value");
await DoSomeAsync();
Assert.AreEqual("value", Context.Read("slot"));

Context.Store("slot", "value");
var value = await ReadContext("slot");
Assert.AreEqual("value", value);

(2)仲良く遊ぶTask.Run()

Context.Store("slot", "value");
var task = Task.Run(() => ReadContext("slot"));
Assert.IsNull(task.Result);

(3)待ちに待った相手と仲良く遊ぶTask

Context.Store("slot", "value");
var value = await Task.Run(() => ReadContext("slot"));
Assert.AreEqual("value", value);

(3)必須ではありませんが、あると便利です。私は今使用していますが、手動で実行されたタスクでも、別のスレッドでのタスクの実行を強制する必要がある実行されたタスクでも、格納されている値にアクセスできるため、 (2)CallContextで失敗します。Task.Factory.StartNew(..., LongRunning)

それを達成する方法はありますか?

4

1 に答える 1

4

あなたの本当の質問はあなたのコメントにあります:

ASP.NET アプリケーションに NHibernate セッションを保存する場所が必要です。HttpContext は、リクエスト コンテキスト内にいる場合は正常に動作します (そして async/await を尊重します) が、手動で実行されたタスクにジャンプすると使用できなくなります。

まず、ASP.NET アプリケーションで「タスクを手動で実行する」ことはまったく避けるべきです。この件に関するブログ記事があります。

第二に、物事を保管することHttpContext.Itemsは一種のハックです。少数の状況で役立つ可能性がありますが、NHibernate セッションを管理する IMO は、アプリケーションに適切に設計する必要があります。つまり、メソッド呼び出しでセッション (またはセッションへのアクセスを提供するサービス) を渡すか、それを必要とする各型に挿入する必要があります。

ですから、あなたが探しているような「コンテキスト」は間違った解決策だと本当に思います。たとえそれが可能だったとしても、そうではありません。

@Noseratio が指摘したように、要件 (2) と (3) の両方を満たすことはできません。で実行されているコードTask.Runがアクセスできるかどうか。両方にはなりません。

お気づきのように、要件 (1) と (3) は論理呼び出しコンテキストによって満たすことができます (Google 社員への注意: これは .NET 4.5 でのみ機能し、不変データを保存する場合にのみ機能します。詳しくは私のブログを参照してください)。

FreeNamedDataSlotのコードの先頭にあるデータ ( ) を手動で削除しない限り、(1) と (2) を満たす簡単な方法はありませんTask.Run。私は別の解決策があるかもしれないと思いますが、それは完全に面倒で、もろく、維持できないすべての await でカスタム awaitables を必要とします。

于 2013-10-16T12:55:30.197 に答える