没有I / O的Async / Await

时间:2017-10-22 07:17:50

标签: c# asynchronous

我刚开始学习async / await。

Stephen Cleary有这篇文章: https://blog.stephencleary.com/2013/11/there-is-no-thread.html

我对I / O了解不多但是......有人可以解释一下如何对不使用I / O的操作应用async / await逻辑吗?

假设我们有一个string[]并想要反转此数组中的所有字符串。

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

然后我想“并行”为数组中的每个元素调用此方法。 我知道像这样的代码不是有效的,但如何使用async / await实现呢?

2 个答案:

答案 0 :(得分:5)

  

有人可以解释一下如何为不使用I / O的操作应用async / await逻辑吗?

您可以在.NET中使用新的async/await来简化并发操作,而不会有任何关于旋转潜在昂贵线程的麻烦。无论操作是CPU绑定还是IO绑定,都可以使用async/await

语法大致相同,只是对于CPU绑定操作,您通常明确地调用Task.Run()或其版本。 TasK可以被认为是表示并发操作的高级构造,而不是 Thread的同义词。 Task.Run将在线程池中的一个可重用线程中执行代码,该线程很可能已在运行。操作完成后,将返回池中。

e.g。

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

在你的场景中,你应该尝试尽可能靠近callstack的顶部调用Task.Run()。这使你的代码:

  1. 更直观
  2. 很明显被调用的操作是异步
  3. 客户端代码可完全控制根任务创建
  4. 为客户端代码提供捕获当前上下文的机会(在GUI代码中特别有用)
  5.   

    然后我想&#34;并行&#34;为数组中的每个元素调用此方法。我知道像这样的代码不是有效的,但如何使用async / await实现呢?

    您可能无法更改实现,但是您可以通过调用方法的方式来使用并发性。

    所以给出你的代码:

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

    你会这样称呼它(让我们假设它是WinForms中的按钮点击处理程序):

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

    再次注意我们使用Task.Run()因为客户端代码知道ReverseString是受CPU限制的。如果要调用I / O绑定的东西,例如WCF或实体框架,请不要使用Task.Run()。

    更多

答案 1 :(得分:0)

使用Parallel.ForEach执行方法并反转数组中的许多字符串。我建议您批量处理字符串,例如10 x 10或100 x 100,具体取决于字符串的大小。因为从线程池为小任务调度线程的开销很大。批量项目时,您将拥有足够大的任务,这种开销可以忽略不计。

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();
});