なぜwebclient.downloadstringtaskasync()ブロックがあるのですか? -New Async API/Syntax/CTP
-
27-09-2019 - |
質問
何らかの理由で、以下のプログラムが開始された後、一時停止があります。私は信じている WebClient().DownloadStringTaskAsync()
原因です。
class Program
{
static void Main(string[] args)
{
AsyncReturnTask();
for (int i = 0; i < 15; i++)
{
Console.WriteLine(i);
Thread.Sleep(100);
}
}
public static async void AsyncReturnTask()
{
var result = await DownloadAndReturnTaskStringAsync();
Console.WriteLine(result);
}
private static async Task<string> DownloadAndReturnTaskStringAsync()
{
return await new WebClient().DownloadStringTaskAsync(new Uri("http://www.weather.gov"));
}
}
私が理解する限り、私のプログラムはすぐに0から15にカウントを開始する必要があります。私は何か間違ったことをしていますか?
元のNetflixのダウンロードサンプルで同じ問題がありました(あなたが取得します CTP) - 検索ボタンを押した後、UIは最初にフリーズします - そしてしばらくしてから、次の映画を読み込んでいる間、それは応答性があります。そして、PDC 2010でのAnders Hejlsbergのプレゼンテーションでは凍結しなかったと思います。
もう一つ。代わりに
return await new WebClient().DownloadStringTaskAsync(new Uri("http://www.weather.gov"));
私は自分の方法を使用しています:
return await ReturnOrdinaryTask();
つまり:
public static Task<string> ReturnOrdinaryTask()
{
var t = Task.Factory.StartNew(() =>
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("------------- " + i.ToString());
Thread.Sleep(100);
}
return "some text";
});
return t;
}
必要に応じて機能します。私はそれが何もロードしないことを意味しますが、それはすぐに始まり、その作業をしている間、メインスレッドをブロックしません。
編集
わかりました、私が今信じているのは: WebClient.DownloadStringTaskAsync
機能はねじ込まれています。このように、最初のブロッキング期間なしで動作するはずです。
static void Main(string[] args)
{
WebClient cli = new WebClient();
Task.Factory.StartNew(() =>
{
cli.DownloadStringCompleted += (sender, e) => Console.WriteLine(e.Result);
cli.DownloadStringAsync(new Uri("http://www.weather.gov"));
});
for (int i = 0; i < 100; i++)
{
Console.WriteLine(i);
Thread.Sleep(100);
}
}
解決
プログラムはしばらくブロックしますが、結果がリモートサーバーから返される前に、forループで実行を再開します。
新しいAsync APIはまだシングルスレッドされていることを忘れないでください。それで WebClient().DownloadStringTaskAsync()
リクエストが準備され、サーバーに送信されるまで、スレッドで実行する必要があります。 await
Main()でのプログラムフローに戻ります。
あなたが見ている結果は、マシンからリクエストを作成して送信するのに時間がかかるという事実によると思います。最初にそれが終了したとき、の実装 DownloadStringTaskAsync
ネットワークIOとリモートサーバーが完了するのを待つことができ、実行を返すことができます。
一方、あなた RunOrdinaryTask
メソッドはタスクを初期化するだけでワークロードを与え、起動するように指示します。その後、すぐに戻ります。それが、使用するときに遅延が見られない理由です RunOrdinaryTask
.
主題に関するいくつかのリンクは次のとおりです。 エリック・リパートのブログ (言語デザイナーの1人)と Jon Skeetの最初のブログ投稿 それについて。エリックには、継続パススタイルに関する5つの投稿のシリーズがあります。 async
と await
本当にです。新機能を詳細に理解したい場合は、CPSとAsyncに関するEricの投稿をお読みください。とにかく、上記の両方のリンクは、非常に重要な事実を説明する上で良い仕事をしています。
- 非同期!=並列
言い換えると、 async
と await
あなたのために新しいスレッドをスピンアップしません。彼らは、あなたがブロッキング操作を行っているときにあなたの通常のフローの実行を再開できるだけで、あなたのCPUがただ座って同期プログラムで何もしない時間で、いくつかの外部操作が完了するのを待っています。
編集
何が起こっているのかを明確にするために: DownloadStringTaskAsync
継続を設定してから電話をかけます WebClient.DownloadStringAsync
, 、同じスレッド上、そして それから 実行をコードに戻します。したがって、ループがカウントを開始する前に表示されているブロッキング時間は、時間がかかる時間です DownloadStringAsync
完了する。 Asyncと待望のプログラムは、プログラムと同じ動作を示す次のプログラムに相当するものに非常に近いです。初期ブロック、カウントスタート、および中央のどこかで、Async OPはコンテンツを終了して印刷します。要求されたURL:
static void Main(string[] args)
{
WebClient cli = new WebClient();
cli.DownloadStringCompleted += (sender, e) => Console.WriteLine(e.Result);
cli.DownloadStringAsync(new Uri("http://www.weather.gov")); // Blocks until request has been prepared
for (int i = 0; i < 15; i++)
{
Console.WriteLine(i);
Thread.Sleep(100);
}
}
注:私は決してこのテーマの専門家ではないので、いくつかの点で間違っているかもしれません。あなたがこれが間違っていると思うなら、私は主題についての私の理解を自由に修正してください - 私はちょうどPDCプレゼンテーションを見て、昨夜CTPで遊んだだけです。
他のヒント
問題は、IE/レジストリ/どこかが遅い場所から検出されているプロキシ構成設定に関連していないことを確認してください。
webclient.proxy = null(またはapp.configで設定を指定する)を設定してみてください。「ブロッキング」期間は最小限でなければなりません。
F5またはCTLR+F5を押して実行していますか? F5では、asyncctplibrary.dllのシンボルを検索するためだけにVSの遅延があります...