编写可以等待的异步进程

Kan*_*bot 5 c# asynchronous async-await

我一直在研究如何将我的(同步)算法转换为异步算法.(TAP)首先,为了清楚起见,这个问题不是关于"Async和Await做什么"(我已经阅读了Stephen Cleary的优秀帖子,例如Async和Await(如果有人有兴趣阅读链接 - 它是非常翔实的)

我还已经阅读了"C#简而言之"的并发章节.

这个问题不是关于异步函数如何使用等待来调用函数.我已经知道了.

不幸的是,在我阅读的几乎所有内容中,它await Task.Delay(10)都用于"创建异步函数".例如:

public async Task<int> GetResult()
{
   int result= await GiveMeTheInt();

}
public async Task<int> GiveMeTheInt() //<--is async needed here? (oops! I just realize it is...
{
  await Task.Delay(100);
  return(10);
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,例如我已经理解了GetResult()函数中异步等待的魔力,但实现GiveMeTheInt()并不是很有用.(它们只是将一个Delay作为一个通用异步函数放在那里)

所以我的问题是关于"GiveMeTheInt"类型的问题(不是那些称之为问题的人).

这个问题

如果我有一个函数编写到目前为止同步的函数,我怎么能将它转换为异步使用?


这不是一个重复的问题,我发现最接近的是转向同步方法异步,其中海报被告知使用已经存在的方法的异步版本.就我而言,这不存在.

我的算法主要包括图像处理,因此实质上是扫描大数组并改变每个像素的值.就像是

void DoSomethingToImage(int[,] Image)
{
  for(int i=0;i<width;i++)
    for(int j=0;j<height;j++)
     {
       Image[i,j]=255;
     }
}
Run Code Online (Sandbox Code Playgroud)

(这是一个虚构的例子,当然操作不同)

我得到的最接近的答案是将函数放在一个Task.Run() 但我不确定这是否是这样做的方法.

任何帮助将不胜感激

pok*_*oke 7

那么看看你的方法:

void DoSomethingToImage(int[,] image)
{
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            image[i, j] = 255;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是异步的吗?显然不是.这只是CPU限制的工作,它会使处理器忙碌一点.因此,单独进行异步并不是一个好的假设.它应该同步运行.

如果您从应用程序的异步部分使用它,该怎么办?您当然不希望用户界面被阻止,因为您正在迭代大量像素.所以解决方案是将工作加载到另一个线程.你这样做使用Task.Run:

await Task.Run(() => DoSomethingToImage(image));
Run Code Online (Sandbox Code Playgroud)

因此,每当DoSomethingToImage从异步方法调用该方法时,您都会编写它.现在,如果你只在异步上下文中使用该方法,你可能会认为Task.Run移入函数可能是有意义的:

Task DoSomethingToImageAsync(int[,] image)
{
    return Task.Run(() => { … });
}
Run Code Online (Sandbox Code Playgroud)

这是一个好主意吗?通常不会,因为现在你正在使该方法看起来是异步的,而事实上并非如此.它所做的只是产生一个新的线程来完成工作,然后它等待线程完成.所以现在你隐藏了那个部分,并且做一个高度同步工作的方法决定应该启动一个线程.这不是一个好主意.并没有什么错保持方法,因为它是表明它是同步的,并调用代码负责决定的如何代码应运行.

如果我有一个函数编写到目前为止同步的函数,我怎么能将它转换为异步使用?

所以,回到你的实际问题,这实际上很难回答.答案可能就是这样:"这取决于".

如果一个方法执行CPU绑定工作,那么最好保持它同步并让调用代码决定如何运行它.如果您在与其他接口(网络,文件系统等)进行交互时主要进行I/O工作,那么这是使其成为异步的良好候选者,特别是考虑到许多这些接口已经提供了与之通信的异步方式他们.


关于你提到的"在这里异步需要?"最后要注意的问题,在您的代码:您需要的async关键字,只要你想使用await它的内部.仅仅存在async关键字并不会使方法异步(甚至返回类型都没有指示).