1

このプログラムに関する観察:

  • このプログラムで F11 をゆっくり押しても、すべての実行が表示されるわけではありません。ProcessURL()

  • このプログラムで F11 キーをすばやく押すと、次の実行がさらに表示されます。ProcessURL()

  • ProcessURL で使用Thread.Sleep(3000);すると、MainUI スレッドが約 30 秒間ハングします。UI の再描画はなく、キャンセル ボタンは使用できません。

ニーズ:

  • ProcessURL のすべての実行をステップ実行するか、ネイティブの Visual Studio ツールまたはオープン ソース アドインを使用して、このように視覚化したいと考えています。

ここに画像の説明を入力

コード

ダウンロードはこちらから

namespace ProcessTasksAsTheyFinish
{
    public partial class MainWindow : Window
    {
        // Declare a System.Threading.CancellationTokenSource.
        CancellationTokenSource cts;

        public MainWindow()
        {
            InitializeComponent();
        }

        private async void startButton_Click(object sender, RoutedEventArgs e)
        {
            resultsTextBox.Clear();

            // Instantiate the CancellationTokenSource.
            cts = new CancellationTokenSource();

            try
            {
                await AccessTheWebAsync(cts.Token);
                resultsTextBox.Text += "\r\nDownloads complete.";
            }
            catch (OperationCanceledException)
            {
                resultsTextBox.Text += "\r\nDownloads canceled.\r\n";
            }
            catch (Exception)
            {
                resultsTextBox.Text += "\r\nDownloads failed.\r\n";
            }

            cts = null;
        }


        private void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            if (cts != null)
            {
                cts.Cancel();
            }
        }


        async Task AccessTheWebAsync(CancellationToken ct)
        {
            HttpClient client = new HttpClient();

            // Make a list of web addresses.
            List<string> urlList = SetUpURLList();

            // ***Create a query that, when executed, returns a collection of tasks.
            IEnumerable<Task<int>> downloadTasksQuery =
                from url in urlList select ProcessURL(url, client, ct);

            // ***Use ToList to execute the query and start the tasks. 
            List<Task<int>> downloadTasks = downloadTasksQuery.ToList();

            // ***Add a loop to process the tasks one at a time until none remain.
            while (downloadTasks.Count > 0)
            {
                    // Identify the first task that completes.
                    Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);

                    // ***Remove the selected task from the list so that you don't
                    // process it more than once.
                    downloadTasks.Remove(firstFinishedTask);

                    // Await the completed task.
                    int length = await firstFinishedTask;
                    resultsTextBox.Text += String.Format
                        ("\r\nLength of the download:  {0}", length);
            }
        }


        private List<string> SetUpURLList()
        {
            List<string> urls = new List<string> 
            { 
                "http://msdn.microsoft.com",
                "http://msdn.microsoft.com/library/windows/apps/br211380.aspx",
                "http://msdn.microsoft.com/en-us/library/hh290136.aspx",
                "http://msdn.microsoft.com/en-us/library/dd470362.aspx",
                "http://msdn.microsoft.com/en-us/library/aa578028.aspx",
                "http://msdn.microsoft.com/en-us/library/ms404677.aspx",
                "http://msdn.microsoft.com/en-us/library/ff730837.aspx"
            };
            return urls;
        }


        async Task<int> ProcessURL(string url, HttpClient client, CancellationToken ct)
        {
            // GetAsync returns a Task<HttpResponseMessage>. 
            HttpResponseMessage response = await client.GetAsync(url, ct);
            // Retrieve the website contents from the HttpResponseMessage.
            byte[] urlContents = await response.Content.ReadAsByteArrayAsync();

            return urlContents.Length;
        }
    }
}
4

1 に答える 1

5

への呼び出しを呼び出しのThread.Sleep 前に置くと仮定するとawait、UI スレッドがロックされたことは完全に理にかなっています。つまり、ブロックしていたのです。メソッドは、完了していないものProcessURLの最初の式に到達するまで同期的に実行されます。awaitそこに着くと、続きをつけて戻ってきます。

したがってThread.Sleep、待機の前に呼び出しがあった場合、LINQ クエリが実行されたときに (を呼び出すとToList、そのメソッドを 7 回続けて呼び出し、UI スレッドで毎回 3 秒間スリープします。UI はロックされます。のThread.Sleep に置くawaitと、UI は同じ時間だけロックアップされますが、小さなバーストになります。

と同等の非同期Thread.Sleepは、次を使用することTask.Delayです。

await Task.Delay(3000);

これは基本的にすぐに戻り、3 秒で発火する継続を付けます。

(デバッグの問題についてはわかりません-これらのステートメントのほとんどをデバッグしようとはしません...何を達成しようとしているのか、またはその理由が正確にはわかりません。ProcessURLそれぞれのブレークポイントにヒットする必要がありますURLですが。)

于 2012-10-26T14:18:12.480 に答える