多个任务。当WPF应用程序

时间:2016-04-08 22:22:30

标签: c# wpf multithreading asynchronous async-await

以下示例代码段通过使用List<string> urls编码技术读取/处理Web Url示例列表async/await的内容来实现多任务处理功能(类似于MSDN演示示例:https://msdn.microsoft.com/en-us/library/jj155756.aspx) 。出于测试目的,Url List<string> urls包含两个错误项目。

清单1. WPF中的错误处理async / await多个任务的实现

    namespace ProcessTasksAsTheyFinish
    {
        public partial class MainWindow : Window
        {
            CancellationTokenSource cts;
            // sample Url list containing erroneous items
            private List<string> SetUpURLList()
            {
                List<string> urls = new List<string> 
                { 
                    "http://msdn.microsoft.com",
                    "http://msdn.microsoft.com/library/windows/apps/br211380.aspx",
                    "error1",
                    "http://msdn.microsoft.com/en-us/library/aa578028.aspx",
                    "error2",
                    "http://msdn.microsoft.com/en-us/library/ms404677.aspx",
                    "http://msdn.microsoft.com/en-us/library/ff730837.aspx"
                };
                return urls;
            }

            public MainWindow() { InitializeComponent(); }

            private async void startButton_Click(object sender, RoutedEventArgs e) {
                resultsTextBox.Clear();
                cts = new CancellationTokenSource();
                try { await AccessTheWebAsync(cts.Token);}
                finally { cts = null; }
            }

            private async Task AccessTheWebAsync(CancellationToken ct) {
                try {
                    HttpClient client = new HttpClient();
                    // sample list of web addresses
                    List<string> urlList = SetUpURLList();
                    // query to create a collection of Tasks
                    IEnumerable<Task<int>> downloadTasksQuery =
                        from url in urlList select ProcessURL(url, client, ct);
                    // run multiple Tasks in async mode
                    await Task.WhenAll(downloadTasksQuery.ToList());
                    resultsTextBox.Text += "\r\nDownloads complete.";
                }
                catch (OperationCanceledException){
                    resultsTextBox.Text += "\r\nDownloads canceled.";
                }
                catch (Exception ex){
                    resultsTextBox.Text += Environment.NewLine + ex.Message;
                }
            }

            private async Task<int> ProcessURL(string url, HttpClient client, CancellationToken ct)
            {
                try
                {
                    HttpResponseMessage response = await client.GetAsync(url, ct);
                    byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
                    resultsTextBox.Text += String.Format("\r\nLength:  {0}", urlContents.Length);
                    return urlContents.Length;
                }
                catch 
                { 
                    //if (cts != null)  cts.Cancel(); 
                    throw; 
                }
            }
        }
    }
// sample output:
// Length:  196315
// Length:  468941
// Length:  158496
// Length:  200790
// Length:  48022
// An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set.

输出包含针对5个有效网址计算的长度信息以及与例外ex.Message对应的错误通知。

目标是以这样的方式修改功能,即第一个异常将完全终止await Task.WhenAll的多任务执行。换句话说,实现&#34;全部或者没有&#34;与等待多个Tasks相关的业务逻辑。

在此示例中,通过使用Exception将以下语句添加到CancellationToken处理块(在清单1中显示为注释行)来实现:

if (cts != null)  cts.Cancel();

输出文本按预期显示,对应于ex.Message

  

提供了无效的请求URI。请求URI必须是   必须设置绝对URI或BaseAddress。

已编辑:我一直在寻找相同的简化实现&#34;全部或全部&#34;功能(允许在第一个错误的Tasks过程中终止整个Task.WhenAll集)而不使用CancellationToken。根据@Stephen Cleary发布的富有洞察力的评论,没有任何超载&#34;快捷方式&#34;选项并没有比当前更好的解决方案(简单性)。

1 个答案:

答案 0 :(得分:2)

没有重载可以提供内置的这种功能。

通常,CancellationTokenSource对象的自动取消不在BCL中(超时便捷方法除外,它根据计时器自动取消)。如果我冒险猜测,我会说BCL团队觉得这些超载的用例太多了,所以对于足够广泛的受众来说,它们不会有用。内置。

相反,适当的解决方案是在任何一个任务出现故障时自己触发CTS,这就是您的代码已经在做的事情。