Owen Flove
Owen Flove

Reputation: 27

Async/Await without I/O

I just started learning about async/await.

There is this article of Stephen Cleary: https://blog.stephencleary.com/2013/11/there-is-no-thread.html

I don't know much about I/O but... Can someone explain me how can I apply the async/await logic for an operation that doesn't use I/O?

Let's say we have a string[] and want to reverse all the strings in this array.

async Task<string> ReverseAsync(string s)
{
    char[] charArray = s.ToCharArray();
    Array.Reverse(charArray);
    return new string(charArray);
}

Then I want to "parallelly" call this method for each element in the array. I understand that a code like this will not be a valid, but how can it be implemented using async/await?

Upvotes: 1

Views: 601

Answers (2)

user585968
user585968

Reputation:

Can someone explain me how can I apply the async/await logic for an operation that doesn't use I/O?

You can use the new async/await in .NET to simplify concurrent operations without all the tedius mucking about of spinning up potentially expensive threads. async/await can be used irrespective of whether the operation is CPU-bound or IO-bound.

The syntax is mostly the same except that for a CPU-bound operation you generally explicity call Task.Run() or a version thereof. TasK can be a thought of as a high level construct to represent concurrent operations and not a synonym for Thread. Task.Run will execute code in one of the re-usable threads in the thread-pool which most likely is already running. Once your operation is complete it is returned to the pool.

e.g.

await Task.Run (() => CalculatePrimeNumbersAsync (10000));

In your scenario you should try to call Task.Run() as close as you can to the top of the callstack. This makes your code:

  1. more intuitive
  2. Obvious that the called operation is async
  3. Client code has complete control over root task creation
  4. Provides client code the chance to capture the current context (particularly useful in GUI code)

Then I want to "parallelly" call this method for each element in the array. I understand that a code like this will not be a valid, but how can it be implemented using async/await?

There is probably not much you can do to change the implementation, however you can certainly make use of concurrency by the way you call the method.

So given your code of:

async Task<string> ReverseAsync(string s)
{
    char[] charArray = s.ToCharArray();
    Array.Reverse(charArray);
    return new string(charArray);
}

You would call it like so (let's assume it's a button click handler in WinForms):

async void OnButtonClicked (object sender, System.EventArgs e)
{
    var reversed = await Task.Run(() => ReverseString ("Miss Piggy is a Muppet"));
}

Note again we use Task.Run() because the client code knows that ReverseString is CPU-bound. Don't use Task.Run() if you are going to call something I/O bound such as WCF or Entity Framework.

More

Upvotes: 5

M.kazem Akhgary
M.kazem Akhgary

Reputation: 19149

use Parallel.ForEach to execute method and reverse many strings in array. i suggest you to process strings in batch, like 10 by 10 or 100 by 100 depending on size of strings. Because overhead of scheduling a thread from thread pool for small tasks is a lot. When you batch items, you will have large enough tasks and this overhead becomes negligible.

int batchSize = 10;
Parallel.ForEach(array.Select((x,i) => new {value = x, index= i})
                      .GroupBy(a => a.index/batchSize),
(item) =>
{
    array[item.index] = item.value.Reverse();
});

Upvotes: 1

Related Questions