1

継続を連鎖させると、予期していなかった順序で実行されているように見えます。

例えば:

for (int i = 1; i < 6; i++)
{
    HttpRequestMessage request = new HttpRequestMessage();

    Task<JsonResult<MyResult>> message = Task.Factory.StartNew<HttpResponseMessage>(() =>
        {
            Console.WriteLine(i + " started");
            return client.SendAsync(request).Result;
        })
        .ContinueWith<JsonResult<MyResult>>((r) =>
            {
                var stringresult = r.Result.Content.ReadAsStringAsync().Result;
                var deserialized = JsonConvert.DeserializeObject<JsonResult<MyResult>>(stringresult);
                Console.WriteLine(deserialized.Id + " deserialized");
                return deserialized;
            })
        .ContinueWith<JsonResult<MyResult>>(m =>
            {
                Console.WriteLine(m.Id + " completed");
                return m.Result;
            });

}

これで、さまざまなリクエストがインターリーブされることを期待していますが、個々のプロセスが開始、逆シリアル化、完了の順に実行されることを期待しています。ただし、次のように、「完了した」継続が逆シリアル化継続の前に実行される場合があります。

1開始
2開始
3開始
4開始
1逆シリアル化、長さ:69
1完了
5開始
5逆シリアル化、長さ:831
2完了
4逆シリアル化、長さ:1022
3完了
3逆シリアル化、長さ:356
4完了
2逆シリアル化、長さ:8785
完了

ここで何が欠けていますか?

編集:

はい、クロージャーについて知っています。実際のコードははるかに長く、もちろんこれを処理しますが、質問に関連するとは思わなかったガフを取り除き、それからみんなが行方不明のガフに集中します!! それは私が見ている質問や問題を変えるものではありません。

4

3 に答える 3

0

@Henrikが言うように、スレッドが実行されるまでに、の値iは変更されます。これにより、スレッドが実際に実行されている順序の決定が正しくないように見えます。

多分i関数にを渡してみてください:

  Task<JsonResult<MyResult>> message = Task.Factory.StartNew<HttpRequestMessage>(state =>  {

            Console.WriteLine(state.ToString() + " started");
            return client.SendAsync(request).Result;
        }, i )
            .ContinueWith<JsonResult<MyResult>>((r) =>
            {
                var stringresult = r.Result.Content.ReadAsStringAsync().Result;
                var deserialized = JsonConvert.DeserializeObject<JsonResult<MyResult>>(stringresult);
                Console.WriteLine(deserialized.Id + " deserialized");
                return deserialized;
            })
            .ContinueWith<JsonResult<MyResult>>(m =>
            {
                Console.WriteLine(m.Id + " completed");
                return m.Result;
            });
于 2013-02-18T15:28:31.217 に答える
0

印刷出力で同じid:sを比較していません。最後の続きをに変更してみてください

        .ContinueWith<JsonResult<MyResult>>(m =>
        {
            Console.WriteLine(m.Result.Id + " completed");
            return m.Result;
        });

したがって、少なくとも継続で同じIDを比較します。

于 2013-02-18T15:32:56.650 に答える
0

したがって、最大の問題は、すべての非同期操作(SendAsyncおよびReadAsStringAsync)で同期待機を実行していることです。これらの同期待機をバックグラウンドスレッドで実行しているだけです。ContinueWithすべての継続には非同期コンポーネントがないため、呼び出しから得られる価値はまったくありません。StartWithコード全体を元の呼び出しの中に入れた方がよいでしょう。それを継続して入れても何も得られません。

これがプログラムの例ですが、非同期操作の同期待機はありません。

for (int i = 1; i < 6; i++)
{
    HttpRequestMessage request = new HttpRequestMessage();

    int id = i;
    Console.WriteLine("{0} started", id);
    var result = client.SendAsync(request)
        .ContinueWith(t =>
        {
            Console.WriteLine("{0} reading", id);
            return t.Result.Content.ReadAsStringAsync();
        })
        .Unwrap()
        .ContinueWith(t =>
        {
            Console.WriteLine("{0} read", id);
            var deserialized = JsonConvert.DeserializeObject<JsonResult<MyResult>>(t.Result);
            Console.WriteLine("{0} deserialized", id);
            return deserialized;
        });
}

また、表示されたコードの1つの問題は、コンソールにログインするときに同じ識別番号を一貫して使用していなかったことです。明確にするために、全体を通してループ変数を使用しました。また、ループ変数を閉じないように、ループ変数のコピーを必ず取得します。また、より興味深い結果が得られるはずのわずかに異なるものをログに記録します。

于 2013-02-18T15:53:50.960 に答える