我想知道如何以“正确”的方式编写您自己的异步方法。
我看过很多这样解释异步/等待模式的帖子:
http://msdn.microsoft.com/en-us/library/hh191443.aspx
// Three things to note in the signature:
// - The method has an async modifier.
// - The return type is Task or Task<T>. (See "Return Types" section.)
// Here, it is Task<int> because the return statement returns an integer.
// - The method name ends in "Async."
async Task<int> AccessTheWebAsync()
{
// You need to add a reference to System.Net.Http to declare client.
HttpClient client = new HttpClient();
// GetStringAsync returns a Task<string>. That means that when you await the
// task you'll get a string (urlContents).
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
// You can do work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork();
// The await operator suspends AccessTheWebAsync.
// - AccessTheWebAsync can't continue until getStringTask is complete.
// - Meanwhile, control returns to the caller of AccessTheWebAsync.
// - Control resumes here when getStringTask is complete.
// - The await operator then retrieves the string result from getStringTask.
string urlContents = await getStringTask;
// The return statement specifies an integer result.
// Any methods that are awaiting AccessTheWebAsync retrieve the length value.
return urlContents.Length;
}
private void DoIndependentWork()
{
resultsTextBox.Text += "Working........\r\n";
}
这适用于任何已经实现此功能的 .NET 方法,例如
- System.IO 操作
- 数据库操作
- 网络相关操作(下载、上传...)
但是,如果我想编写自己的方法,但需要相当长的时间才能完成,而我无法使用任何方法,而且重负载在上面示例的 DoIndependentWork
方法中,该怎么办?
在这种方法中我可以做到:
- 字符串操作
- 计算
- 处理我自己的元素
- 聚合、比较、过滤、分组、处理内容
- 列表操作、添加、删除、复制
我又一次偶然发现了很多帖子,人们只是在做以下事情(再次以上面的例子为例):
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
await DoIndependentWork();
string urlContents = await getStringTask;
return urlContents.Length;
}
private Task DoIndependentWork()
{
return Task.Run(() => {
//String manipulations
//Calculations
//Handling my own objects
//Aggregating, comparing, filtering, grouping, handling stuff
//List operations, adding, removing, coping
});
}
您可能会注意到变化是 DoIndependentWork
现在返回一个 Task 并且在 AccessTheWebAsync
任务中该方法得到一个 await
。
重负载操作现在封装在 Task.Run()
中,这就是全部吗?
如果仅此而已,我唯一需要做的就是为我的库中的每个方法提供异步方法,如下所示:
public class FooMagic
{
public void DoSomeMagic()
{
//Do some synchron magic...
}
public Task DoSomeMagicAsync()
{
//Do some async magic... ?!?
return Task.Run(() => { DoSomeMagic(); });
}
}
如果你能向我解释一下就好了,因为即使是像这样的高票问题: How to write simple async method?只用现有的方法解释它,并且只使用 asyn/await 模式,就像上面提到的问题的评论一样,直截了当: How to write simple async method?
最佳答案
实际答案
您可以使用 TaskCompletionSource
来做到这一点,它有一个 Promise Task它不执行任何代码,只执行:
"Represents the producer side of a Task unbound to a delegate, providing access to the consumer side through the Task property."
当您开始异步操作时,您将该任务返回给调用者,并在您结束它时设置结果(或异常/取消)。确保操作真的是异步的是你的责任。
这是 Stephen Toub's AsyncManualResetEvent
中这种 root of all async 方法的一个很好的例子实现:
class AsyncManualResetEvent
{
private volatile TaskCompletionSource<bool> _tcs = new TaskCompletionSource<bool>();
public Task WaitAsync() { return _tcs.Task; }
public void Set() { _tcs.TrySetResult(true); }
public void Reset()
{
while (true)
{
var tcs = _tcs;
if (!tcs.Task.IsCompleted ||
Interlocked.CompareExchange(ref _tcs, new TaskCompletionSource<bool>(), tcs) == tcs)
return;
}
}
}
背景
使用 async-await
基本上有两个原因:
- 改进的可伸缩性:当您有
I/O
密集型工作(或其他固有的异步操作)时,您可以异步调用它,因此您释放调用线程,它是能够同时做其他工作。 - 卸载:当您有
CPU
密集型工作时,您可以异步调用它,这会将一个线程的工作转移到另一个线程(主要用于GUI
线程)。
因此,大多数 .Net
框架的异步调用都支持开箱即用的 async
并且为了卸载,您可以使用 Task.Run
(如你的例子)。您真正需要自己实现async
的唯一情况是当您创建一个新的异步调用(I/O
或 async synchronization constructs for例子)。
这些情况极为罕见,这就是为什么您大多会找到以下答案的原因
"Only explains it with already existing methods and just using
async/await
pattern"
您可以在 The Nature of TaskCompletionSource 中更深入地了解
关于c# - 编写自己的异步方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24953808/