简体   繁体   中英

How to run parallel tasks on Windows Phone?

I'm building a WP8 app and I need to perform around 30 web requests. These requests don't depend on each other so they could be parallelized.

My code looks like this (simplified/pseudocode):

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

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

When I look at Fiddler, the requests are all performed sequantial; it takes a few seconds to perform and process all of them. However, I don't want the code to wait until 1 request is finished before moving to the next one, I want to perform multiple requests at the same time.

Normally I would use Parallel.Invoke() or Parallel.ForEach() or something like that to do this, but apparently the Parallel library is not available in Windows Phone 8.

So what's the best way to accomplish this? Task.Factory.StartNew() ? new Thread() ?

There's no need to run each request on a separate thread. You can just as easily do this:

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

This code takes the collection of uris and starts an HTTP download for each one ( Select(...) ). Then it asynchronously waits for them all to complete ( WhenAll ). All the data is then processed in the second line of code.

However, it's likely that the Windows Phone runtime will limit the maximum number of requests you can have to the same server.

You are using await with the task that you create - which means you are waiting for the call to finish before you continue the method. Your foreach isn't parallelized, as you noted, so what you're essentially doing here is a number of serial requests.

You could make this run as you (probably) intend using the Task.WaitAll method. Something like this should suffice:

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);

Do note that this also parallelizes the processing of your data (that is, it will call .Process in parallel also), which your original code did not.

I'd also add that you probably don't want to run 30 requests at once, unless they're to different servers. Making 30 simultaneous requests to Uris on the same server is unlikely to improve your processing time. (Fortunately, the TPL will likely take care of this for you as it'll limit the parallelism somewhat.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM