【问题标题】:How to run parallel tasks on Windows Phone?如何在 Windows Phone 上运行并行任务?
【发布时间】:2013-11-29 14:53:11
【问题描述】:

我正在构建一个 WP8 应用程序,我需要执行大约 30 个网络请求。这些请求不相互依赖,因此可以并行化。

我的代码如下所示(简化/伪代码):

foreach (Uri uri in uris)
{
    var rawData = await Task.Run(() => httpClient.GetStringAsync(uri).ConfigureAwait(false));

    var processedData = dataProcessor.Process(rawData);
    processedDataCollection.Add(processedData);
}

当我查看 Fiddler 时,请求都是按顺序执行的;执行和处理所有这些需要几秒钟。但是,我不希望代码等到 1 个请求完成后再移动到下一个请求,我想同时执行多个请求。

通常我会使用 Parallel.Invoke()Parallel.ForEach() 或类似的东西来执行此操作,但显然 Parallel 库在 Windows Phone 8 中不可用。

那么最好的方法是什么? Task.Factory.StartNew()? new Thread()?

【问题讨论】:

    标签: c# multithreading asynchronous windows-phone-8 parallel-processing


    【解决方案1】:

    无需在单独的线程上运行每个请求。你可以很容易地做到这一点:

    var raw = await Task.WhenAll(uris.Select(uri => httpClient.GetStringAsync(uri)));
    var processed = raw.Select(data => dataProcessor.Process(data)).ToArray();
    

    此代码获取uris 的集合并为每个集合启动一个HTTP 下载(Select(...))。然后它异步等待它们全部完成 (WhenAll)。然后在第二行代码中处理所有数据。

    但是,Windows Phone 运行时可能会限制您对同一服务器的最大请求数。

    【讨论】:

    • 我真的很喜欢这个。非常紧凑和优雅。我无法真正让它与其他代码一起使用,但这非常有效。如果您能解释一下这些步骤以及为什么它实际上有效,您的帖子会更有帮助。
    • 已更新以包含更多说明。
    【解决方案2】:

    您正在将await 用于您创建的任务 - 这意味着您正在等待调用完成,然后再继续该方法。正如您所指出的,您的 foreach 没有并行化,因此您在这里所做的基本上是一些串行请求。

    您可以使用Task.WaitAll 方法按照您(可能)想要的方式运行此程序。像这样的东西就足够了:

    var tasks = new List<Task>();
    
    foreach (Uri uri in uris)
    {
        var thisTask = Task.Run(() => 
                           { 
                             httpClient.GetStringAsync(uri).ConfigureAwait(false);
                             var processedData = dataProcessor.Process(rawData);
                             processedDataCollection.Add(processedData);
                           });
    
        tasks.Add(thisTask);
    }
    
    Task.WaitAll(tasks);
    

    请注意,这也会并行处理您的数据(也就是说,它也会并行调用 .Process),而您的原始代码没有这样做。

    我还要补充一点,您可能想一次运行 30 个请求,除非它们发往不同的服务器。在同一台服务器上同时向 Uris 发出 30 个请求不太可能缩短您的处理时间。 (幸运的是,TPL 可能会为您解决这个问题,因为它会在一定程度上限制并行性。)

    【讨论】:

    • GetStringAsync() 在您的示例中返回什么?我只能让它返回Task&lt;T&gt;ConfiguredTaskAwaitable&lt;T&gt;。我如何将它用于 Process() 方法?我需要在GetStringAsync 方法上调用.Result 吗?
    • 使用await Task.WhenAll而不是Task.WaitAll不是更好吗?还是他们有不同的结果?
    • Task.WhenAll 创建一个新任务,直到所有其他任务都完成后才能完成; Task.WaitAll 只是等待他们完成。如果您不在乎它们何时完成并且可以继续进行,则可以完全省略该调用。关于GetStringAsync....
    • ... 我所做的只是包装您已经调用的代码,以展示如何使其并行运行。你没有对返回值做任何事情,你还没有真正指定你想要做什么,所以我没有改变那个代码。 GetStringAsync 返回一个任务,因为它是一个异步方法。如果你想得到结果,你可以使用string s = await httpClient.GetStringAsync(uri); - 我不确定你打电话给.ConfigureAwait(false)的意图是什么。
    猜你喜欢
    • 1970-01-01
    • 2015-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-19
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    相关资源
    最近更新 更多