我终于研究了async和await关键字,我有点"得到",但我见过的所有例子都在.Net框架中调用异步方法,例如这个调用HttpClient.GetStringAsync().
我不太清楚的是这种方法会发生什么,以及我如何编写自己的"等待"方法.它是否像包装我想在Task中异步运行的代码并返回那样简单?
Jan*_*s F 78
这很简单
Task.Run(() => ExpensiveTask());
Run Code Online (Sandbox Code Playgroud)
为了使它成为一个等待的方法:
public Task ExpensiveTaskAsync()
{
return Task.Run(() => ExpensiveTask());
}
Run Code Online (Sandbox Code Playgroud)
这里重要的是返回一个任务.该方法甚至不必标记为异步.(只是进一步阅读它进入图片)
现在这可以称为
async public void DoStuff()
{
PrepareExpensiveTask();
await ExpensiveTaskAsync();
UseResultsOfExpensiveTask();
}
Run Code Online (Sandbox Code Playgroud)
注意,方法签名在这里说async,因为该方法可以将控制返回给调用者直到ExpensiveTaskAsync()返回.而且,在这种情况下昂贵意味着耗时,如网络请求或类似的.要将繁重的计算发送到另一个线程,通常最好使用"旧"方法,即System.ComponentModel.BackgroundWorker用于GUI应用程序或System.Threading.Thread.
svi*_*ick 13
我将如何编写自己的"等待"方法?它是否像包装我希望在a中异步运行
Task并返回的代码一样简单?
这是一个选项,但它很可能不是您想要做的,因为它实际上并没有为您提供异步代码的许多优点.有关更多详细信息,请参阅Stephen Toub 应该为同步方法公开异步包装器吗?
一般来说,方法是不可取的,类型是.如果您希望能够编写类似的东西await MyMethod(),则MyMethod()必须返回Task,Task<T>或者自定义await类型.使用自定义类型是一种罕见的高级方案; 使用Task,你有几个选择:
async和编写你的方法await.这对于异步编写动作很有用,但它不能用于最内部的await调用.Task使用其中一种方法创建Task,例如Task.Run()或Task.FromAsync().TaskCompletionSource.这是最通用的方法,它可以用于await从将来发生的任何事情创建有效的方法.nos*_*tio 11
......我将如何编写自己的"等待"方法.
回归Task不是唯一的方法.你可以选择创建一个自定义awaiter(通过实现GetAwaiter和INotifyCompletion),这是一个很好的阅读:"等待任何事情".返回自定义awaiters的.NET API示例:Task.Yield(),Dispatcher.InvokeAsync.
// don't use this in production
public static class SwitchContext
{
public static Awaiter Yield() { return new Awaiter(); }
public struct Awaiter : System.Runtime.CompilerServices.INotifyCompletion
{
public Awaiter GetAwaiter() { return this; }
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation)
{
ThreadPool.QueueUserWorkItem((state) => ((Action)state)(), continuation);
}
public void GetResult() { }
}
}
// ...
await SwitchContext.Yield();
Run Code Online (Sandbox Code Playgroud)
是的,从技术上讲,您只需要从方法中返回 aTask或即可实现可等待的方法。Task<Result>async
这支持基于任务的异步模式。
但是,有多种实施 TAP 的方法。有关详细信息,请参阅实现基于任务的异步模式。
(但所有这些实现仍然返回Taskor Task<Result>,当然。)
只需将您的方法转换为任务。像@Romiox 一样,我通常使用这个扩展名:
public static partial class Ext
{
#region Public Methods
public static Task ToTask(Action action)
{
return Task.Run(action);
}
public static Task<T> ToTask<T>(Func<T> function)
{
return Task.Run(function);
}
public static async Task ToTaskAsync(Action action)
{
return await Task.Run(action);
}
public static async Task<T> ToTaskAsync<T>(Func<T> function)
{
return await Task.Run(function);
}
#endregion Public Methods
}
Run Code Online (Sandbox Code Playgroud)
现在让我们说你有
void foo1()...
void foo2(int i1)...
int foo3()...
int foo4(int i1)...
Run Code Online (Sandbox Code Playgroud)
...
然后你可以像@Romiox一样声明你的[async Method]
async Task foo1Async()
{
return await Ext.ToTask(() => foo1());
}
async Task foo2Async(int i1)
{
return await Ext.ToTask(() => foo2(i1));
}
async Task<int> foo3Async()
{
return await Ext.ToTask(() => foo3());
}
async Task<int> foo4Async(int i1)
{
return await Ext.ToTask(() => foo4(i1));
}
Run Code Online (Sandbox Code Playgroud)
或者
async Task foo1Async()
{
return await Ext.ToTaskAsync(() => foo1());
}
async Task foo2Async(int i1)
{
return await Ext.ToTaskAsync(() => foo2(i1));
}
async Task<int> foo3Async()
{
return await Ext.ToTaskAsync(() => foo3());
}
async Task<int> foo4Async(int i1)
{
return await Ext.ToTaskAsync(() => foo4(i1));
}
Run Code Online (Sandbox Code Playgroud)
...
现在您可以对任何 fooAsync 方法使用 async 和 await,例如 foo4Async
async Task<int> TestAsync () {
///Initial Code
int m = 3;
///Call the task
var X = foo4Async(m);
///Between
///Do something while waiting comes here
///..
var Result = await X;
///Final
///Some Code here
return Result;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
38360 次 |
| 最近记录: |