简体   繁体   中英

How to process multiple threads at once using Task Parallel Library

I'm using Asp.Net 4.0.

I also have a HashSet from which I want to create and run tasks asynchronously, waiting for them all to finish with a timeout applied. The code below is what I have so far, but given that there are so many ways to skin a cat with TPL, can this be improved on, or are there any critical issues?

        TaskWrapper[] taskWrappers = new TaskWrapper[nodeCount];
        Task<ResponseWrapper>[] tasks = new Task<ResponseWrapper>[nodeCount];

        int i = 0;
        foreach (var n in rt.Nodes)
        {
            tasks[i] = Task<ResponseWrapper>.Factory.StartNew(() => MyMethod.Submit(n.Data, timeout));

            taskWrappers[i].LeadPointID = n.LeadPointID;
            // other wrapper stuff;
            taskWrappers[i].Task = tasks[i];

            i++;
        }

        Task.WaitAll(tasks, timeout);

Having read the article kindly provided, it seems like this kind of code structure would be the preferred method of working:

class MyService2
{
    public int CalculateMandelbrot()
    {
        // Tons of work to do in here!
        for (int i = 0; i != 10000000; ++i)
            ;
        return 42;
    }
}

private async void MyButton_Click(object sender, EventArgs e)
{
  await Task.Run(() => myService.CalculateMandelbrot());
}

However, as I've previously pointed out I don't have access to VS2012, so given that as a starting point, is there a VS2010 equivalent to this pattern?

Task.WaitAll will block your main thread until all other tasks have completed. That's one less thread that could be being used to server more requests.

Instead, you should be using await Task.WhenAll . However, WhenAll does not have an overload that takes a timeout. A possible workaround is to combine it with a Task.Delay , and then wait for either all your tasks to finish or the delay task to finish:

await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(timeout));

If you don't have access to VS 2012, then an alternative would be to attach a continuation task to WhenAny , and return that task. The framework will take care of the rest.

public Task<string> Post()
{
    var tasks = //...
    var continuation = Task.WhenAny(Task.WhenAll(tasks), Task.Delay(timeout))
                           .ContinueWith(whenAnyTask => 
        {
             //the rest of your code
             return "Hello";
        };

    return continuation;
}

More importantly: do not use Task.Run (or StartNew ) on an ASP.NET application!

You're taking threads from the threadpool to serve a client faster, but those threads could be being used to serve more clients! So you're telling other clients "hold on a minute, i'm focusing my resources on serving this guy first". You're also introducing a lot of needless overhead.

In a web app, it's good practice to use only one thread at a time to serve a client, and use asynchronous code for async I/O only.


Edit : Aron

Each thread in .net (x86) uses 1MB of RAM or 4MB on (x64). Even a fairly beefy server with 16GB of ram would ONLY be able to therefore run 4000 threads (assuming no memory usage anywhere else). That means that IF each request runs 4 threads, you can only concurrently handle 1000 requests.

Whereas a node.js server (which uses a similar model to ASP.Net async/await) is easily able to handle over 10000 concurrent requests on a single thread (read a much smaller memory footprint).


For a more detailed explanation, see Stephen Cleary's Task.Run Etiquette Examples: Don't Use Task.Run in the Implementation .

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