Jeff
Jeff

Reputation: 13199

What is the best way to do multithreading or asynchronous task in .NET with return value?

What would be the best way to do multithreading or asynchronous task in the following situation in C#?

The simplified situation:

A http request needs to make 5 or more web service calls. Upon completion each web service call will receive and return a string list as a result. The caller (of 5 web service calls) need to merge the 5 results into a single string list and return it to the http caller.

Because each thread needs to return a value in the end so I am wondering if Asynchronous Delegates is the way to go. Because I am not so experienced in this area so I am asking this questions and/or suggestions.

Thank you!

Upvotes: 4

Views: 3147

Answers (3)

Mikael Svenson
Mikael Svenson

Reputation: 39695

Here's a short piece og code using .Net 4.0 which utilizes the new System.Collections.Concurrent which encapsulates the concurrency code:

class StackOverflowParalell
{
    public void Execute()
    {
        List<int> codeParam = new List<int>(){1,2,3};
        ConcurrentBag<string> result = new ConcurrentBag<string>();
        Parallel.For(0, codeParam.Count, i => DoSometing(i).ForEach( result.Add ));
        // return result here as List, Array....
    }

    List<string> DoSometing(int value)
    {
        return new List<string>(){"1","2","3","4"};
    }
}

Upvotes: 1

Michael Meadows
Michael Meadows

Reputation: 28426

You need to use a callback to accomplish what you're asking.

The easiest way to do this if you're not using the 4.0 framework is as follows:

var strings = new List<string>();
for (var i = 0; i < 5; i++)
{
    ThreadPool.QueueUserWorkItem((x) => strings.AddRange(SomeWebServiceCall(i)));
}

This requires some synchronization after the loop to ensure the threads complete before you move on. In the 4.0 framework, the Task Parallel Library does that work for you:

Parallel.For(0, 5, i => strings.AddRange(someWebServiceCall(i)));

Asynchronous delegates were useful when the 1.0 framework came out, but are a lot of extra framework to deal with since the addition of anonymous delegates in 2.0. In 4.0, the TPL makes them even more irrelevant. IAsyncResult relies on an explicit callback, and you can now use implicit callbacks (as demonstrated above).

Upvotes: 0

James
James

Reputation: 82136

You should have a look at QueueUserWorkItem. This would allow you to do each call on a separate thread and get the string value based on the particular call e.g.

ManualResetEvent[] calls = new ManualResetEvent[5];
string[] results = new string[5];

calls[0] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(t => 
{
    results[0] = // do webservice call
    calls[0].Set();
});

calls[1] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(t => 
{
    results[1] = // do webservice call
    calls[1].Set();
});

....
// wait for all calls to complete
WaitHandle.WaitAll(calls);
// merge the results into a comma delimited string
string resultStr = String.Join(", ", results);

Upvotes: 5

Related Questions