2
votes

Alright, I want to keep this short and precise, I'm trying to find the most efficient way to get a large amount of HttpWebRequests completed but I'm slightly confused, if I have a List of tasks and I use the Task.WaitAll function to await until all tasks have completed, is it overkill to make the Task (Action) in the list also an async task? Maybe I can explain myself better in code:

        for (int i = 0; i < 50; i++)
        {
            taskList.Add(Task.Run(() => DoSomething()));
        }
        Task.WaitAll(taskList.ToArray());

Ok so pretty simple, I have a for loop that'll run the DoSomething method on available threads within the ThreadPool, now let's take two different looks at how I can implement this DoSomething() function

public void DoSomething()
{
Send off the HttpWebRequest here, with no awaits or any async programming
}

OR

public Task<ResponseData> DoSomething()
{
Write the request here that awaits for responses, streams etc
}

If I am already sending the DoSomething function off to the Task.Run function doesnt that already mean it's running on it's own Thread in the ThreadPool ? meaning making the DoSomething function an actual task and implementing awaits/async functionality within that scope becomes redundant? wouldnt that just waste more resources?

1
Impossible to answer without more context. Does DoSomething() do anything other than make your HTTP request? Do you need for it to do something after the request is done? If all you're doing is the request, then you should use the async request API, return from DoSomething() the Task representing the request, and just add that to your list instead of using Task.Run(). If DoSomething() has more processing to do after the request, you should do the same, but you can await in it. Either way, it's unlikely you need Task.Run(). But who can tell, since you didn't share code. - Peter Duniho
So a function that returns a task is already accessing a thread on the threadpool as if I was passing a non-task returning function into Task.Run? So Task.Run(() => DoSomething()); would be the same as creating a function that returns a task? - Reece Cooper
"a function that returns a task is already accessing a thread on the threadpool?" -- not necessarily, no. But it is operating asynchronously, and that's what you care about in the code above. Don't confuse "asynchronous" with "concurrent" or "threaded". The two are closely related, but are not the same. There are asynchronous mechanisms that don't rely on an active thread. - Peter Duniho
So one last thing, iterating over a collection of objects and calling a function which returns a task in each iteration with awaits in that scope would give the same affect as adding Task.Run(() => NonTaskFunction) to a list of tasks and then awaiting it? But the more optimal, and 'proper' way of doing this would be to actually use the task api and implement the appropriate function yes? Iterating over a collection of objects in which the only thing I do is call the async task would give me the parralel/multithreaded aspect im looking for - Reece Cooper
So to conclude, having an async Task DoSomething() containing awaits and calling Task.Run(() => DoSomething is completely useless and unnecessary as a Task is already 'running' anyway as the function signature implies. I should only use Task.Run if I have a function or functions that need to be completed on a separate thread and said function isn't already a Task itself I guess - Reece Cooper

1 Answers

2
votes

If I am already sending the DoSomething function off to the Task.Run function doesnt that already mean it's running on it's own Thread in the ThreadPool ? meaning making the DoSomething function an actual task and implementing awaits/async functionality within that scope becomes redundant?

Opposite - you are wasting resources when you using another thread (Task.Run) for the method which "do nothing" - waiting for the response.

await Task.Run(() => DoSomethingSynchronously) and await DoSomethingAsynchronously() are different things, because properly created async-await method will executes on the one thread.
In your case it will send request and return execution back to the caller. After response arrived it will continue execution after await.

So using Task.Run with methods which do nothing - only waiting for response become wasting of resources(threads).

Because your DoSomething method works with external resource (webervices), you don't need to worry about ThreadPool and threads at all. All tasks can be done asynchronously in one thread with async-await approach.