You have 4 options
- Use
System.Threading's Thread
This is probably the worst option, since it doesn't take advantage of the ThreadPool. And since you are spinning up a considerable amount of threads (each one has approx. 1Mb of overhead, because each one has its stack among other things) - Use
ThreadPoll.QueueUserWorkItem
This is better, since it takes advantage of the ThreadPool. However it is less flexible than other methods since it won't allow you to return anything from the callback - Use Task.Factory.StartNew
If for some reason you can't use async/await this is the way to go. It takes advantage of the ThreadPool and is very flexible in terms of how it is used.StartNew<T>
returnsTask<T>
which you can hold to and when you need the result you can call 'task.Result' which will block the calling thread until the task finishes. - Use
async/await
This is the easiest and the most in vogue way of doing async these days, and rightly so. It is just syntactic sugar for (3).
To use async/await your method has to return Task<T>
, in your case Task<ResponseObject>
. By convention the method name end with Async and has the keyword async
In your example, you can change ServiceRequest's Start method so that it is async:
public async Task<ResponseObject> StartAsync()
{
//make the request using await
//for example return await caller.PerformRequestAsync
//an important note here, if the method you need to call is not async, you can use await Task.Factory.StartNew<ResponseObject>(method that returns ResponseObject)
return response; //response is an instance of ResponseObject
}
And then you can change StartServiceRequests and make sure it is called periodically (instead of doing it on start [this is just a suggestion]):
private async void StartServiceRequestsAsync()
{
IEnumerable<Task<ResponseObject>> requests = new List<Task<ResponseObject>>();
foreach (ServiceRequest s in ServiceCommuncators)
{
requests.Add(s.StartAsync()); //this is non-blocking
}
foreach(var executingRequest in requests)
{
ResponseObject response = await executingRequest;
//do something with response
}
}
This will take advantage of the ThreadPool, which will manage the number of threads currently executing and will manage the creation and disposing of existing threads. Sometimes it is important to know how new threads get added to the ThreadPool. A new thread won't necessarily be created immediately when you use Task.Factory.StartNew (or you use async/await).
There's a .5sec wait that checks if the ThreadPool doesn't change (meaning that all threads are doing work) then new threads are added (again, adding a thread has a significant cost).
But in your case you want to perform 50 parallel requests (which you know each will take time, i.e. more than .5sec) so you want all to start. You can change the minimum number of threads in the ThreadPool(SetMinThreads) and set it to 50 (this doesn't mean that 50 threads will immediately be created in the ThreadPool, it just means there's .5sec no wait until the ThreadPool reaches 50 threads).
Here's an example:
int minWorker, minIOC;
// Get the current settings.
ThreadPool.GetMinThreads(out minWorker, out minIOC);
// Change the minimum number of worker threads to 50, but
// keep the old setting for minimum asynchronous I/O
// completion threads.
if (ThreadPool.SetMinThreads(50, minIOC))
{
// The minimum number of threads was set successfully.
}
else
{
// The minimum number of threads was not changed.
}