首先,为了清楚起见,这个问题并不是关于“Async和Await做什么”(我已经阅读了Stephen Cleary的优秀帖子,例如 Async and 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); }
例如,在这个例子中,我已经理解了GetResult()函数中异步等待的魔力,但是GiveMeTheInt()的实现并不是非常有用.(它们只是将一个Delay作为一般异步函数放在那里)
所以我的问题是关于“GiveMeTheInt”类型的问题(不是那些称之为问题的人).
这个问题
如果我有一个函数编写到目前为止同步的函数,我怎么能将它转换为异步使用?
这不是一个重复的问题,我发现最接近的是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()中,但我不确定这是否是这样做的.
任何帮助将不胜感激
解决方法
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(() => { … }); }
这是一个好主意吗?通常不会,因为现在你正在使该方法看起来是异步的,而事实上并非如此.它所做的只是产生一个新的线程来完成工作,然后它等待线程完成.所以现在你隐藏了那个部分,并且做一个高度同步工作的方法决定应该启动一个线程.这不是一个好主意.保持方法不变,显示它是同步的,并使调用代码负责决定应该如何运行代码.
If I have an algorithm written in a function that so far has been synchronous,how can I convert this to be used asynchronously?
所以,回到你的实际问题,这实际上很难回答.答案可能就是这样:“这取决于”.
如果一个方法执行cpu绑定工作,那么最好保持它同步并让调用代码决定如何运行它.如果您在与其他接口(网络,文件系统等)进行交互时主要进行I / O工作,那么这是使其成为异步的良好候选者,特别是考虑到许多这些接口已经提供了与之通信的异步方式他们.
关于你的“在这里需要异步吗?”问题的最后一个注意事项:你想在其中使用await时需要async关键字.仅仅存在async关键字并不会使方法异步(甚至返回类型都没有指示).