我一直在研究如何将我的(同步)算法转换为异步算法。 (TAP) 首先,为了清楚起见,这个问题不是关于"什么是Async和Await做什么" (我已经阅读了Stephen Cleary的优秀帖子,例如Async and Await(如果有兴趣的人请阅读链接 - 这是非常有用的信息)
我已经阅读了关于" C#的并发性的章节,简而言之"。
这个问题不是关于async函数如何使用await来调用函数。我已经知道了。
不幸的是,在我阅读的几乎所有内容中,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);
}
在这个例子中,例如我已经理解了GetResult()
函数中异步等待的魔力,但是GiveMeTheInt()
的实现并不是很有用。(它们只是将一个Delay作为一个通用的异步函数和留在那里)
所以我的问题是关于&#34; GiveMeTheInt&#34;类型的问题(不是那些打电话给他们的人)。
问题
如果我在目前为止同步的函数中编写了算法,如何将其转换为异步使用?
这不是一个重复的问题,我发现的最接近的是Turning a Syncronous method async,其中海报被告知使用已经存在的方法的异步版本。就我而言,这不存在。
我的算法主要由图像处理组成,因此实质上是扫描大数组并改变每个像素的值。像
这样的东西void DoSomethingToImage(int[,] Image)
{
for(int i=0;i<width;i++)
for(int j=0;j<height;j++)
{
Image[i,j]=255;
}
}
(这是一个虚构的例子,当然操作不同)
我得到的最接近的答案是将函数放在Task.Run()
内,但我不确定这是否是这样做的。
非常感谢任何帮助
答案 0 :(得分:7)
所以看看你的方法:
void DoSomethingToImage(int[,] image)
{
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
image[i, j] = 255;
}
}
}
这是异步的吗?显然不是。这只是CPU限制的工作,它会使处理器忙碌一点。因此,单独进行异步并不是一个好的假设。它应该同步运行。
如果您从应用程序的异步部分使用它,该怎么办?您当然不希望用户界面被阻止,因为您正在迭代大量像素。所以解决方案是将工作加载到另一个线程。您可以使用Task.Run
执行此操作:
await Task.Run(() => DoSomethingToImage(image));
因此,只要从异步方法调用DoSomethingToImage
方法,就会编写它。现在,如果您只在异步上下文中使用该方法,您可能会认为将Task.Run
移动到函数中可能是有意义的:
Task DoSomethingToImageAsync(int[,] image)
{
return Task.Run(() => { … });
}
这是个好主意吗?通常不会,因为现在你正在使该方法看起来是异步的,而事实上并非如此。它所做的只是产生一个新的线程来完成工作,然后它等待线程完成。所以现在你隐藏那部分并且还使一个方法做高度同步工作决定应该启动一个线程。这不是一个好主意。保持方法不变,显示它是同步的,并使调用代码负责决定如何运行该代码
,这没有任何问题。如果我在目前为止同步的函数中编写了算法,如何将其转换为异步使用?
所以,回到你的实际问题,这实际上很难回答。答案可能就是这样:“它取决于”。
如果一个方法执行CPU绑定工作,那么最好保持它同步并让调用代码决定如何运行它。如果您在与其他接口(网络,文件系统等)进行交互时主要进行I / O工作,那么 是使其成为异步的良好候选者,特别是考虑到许多这些接口将会已经提供了与它们进行通信的异步方式。
关于您的“在这里需要异步吗?”问题的最后一个注意事项:您需要async
关键字,只要想要在其中使用await
。仅仅存在async
关键字并不会使方法异步(甚至返回类型也没有指示)。