C# 如何写一个;“等待”;方法?
我最后研究了async&await关键字,我有点“获取”,但我看到的所有示例都调用.Net framework中的异步方法,例如调用C# 如何写一个;“等待”;方法?,c#,async-await,C#,Async Await,我最后研究了async&await关键字,我有点“获取”,但我看到的所有示例都调用.Net framework中的异步方法,例如调用HttpClient.GetStringAsync() 我不太清楚的是,在这种方法中会发生什么,以及我将如何编写自己的“等待”方法。它是否像包装我希望在任务中异步运行的代码并返回它那样简单?它就像 Task.Run(() => ExpensiveTask()); 要使其成为一种值得期待的方法: public Task ExpensiveTaskAsync()
HttpClient.GetStringAsync()
我不太清楚的是,在这种方法中会发生什么,以及我将如何编写自己的“等待”方法。它是否像包装我希望在任务中异步运行的代码并返回它那样简单?它就像
Task.Run(() => ExpensiveTask());
要使其成为一种值得期待的方法:
public Task ExpensiveTaskAsync()
{
return Task.Run(() => ExpensiveTask());
}
这里最重要的是返回一个任务。该方法甚至不必标记为异步。(只需再多读一点就可以了)
现在这可以称为
async public void DoStuff()
{
PrepareExpensiveTask();
await ExpensiveTaskAsync();
UseResultsOfExpensiveTask();
}
注意,这里的方法签名是
async
,因为该方法可能会将控制权返回给调用方,直到ExpensiveTaskAsync()
返回为止。此外,在这种情况下,昂贵意味着耗时,如web请求或类似请求。要将繁重的计算发送到另一个线程,通常最好使用“旧”方法,即GUI应用程序的System.ComponentModel.BackgroundWorker
或System.Threading.thread
是,从技术上讲,您只需要从async
方法返回任务
或任务
,即可实现可等待的方法
这支持了这一点
然而,有几种实现TAP的方法。有关详细信息,请参阅
(当然,所有这些实现仍然返回Task
或Task
)
。。。我将如何编写自己的“等待”方法
返回任务
不是唯一的方法。您可以选择创建自定义等待器(通过实现GetAwaiter
和),下面是一个很好的阅读:。返回自定义等待程序的.NET API示例:Task.Yield()
,Dispatcher.InvokeAsync
我有一些关于定制等待者的帖子,例如:
我将如何编写自己的“等待”方法?它是否像在任务
中包装我想要异步运行的代码并返回那样简单
这是一种选择,但它很可能不是您想要做的,因为它实际上没有给您异步代码的许多优点。有关详细信息,请参阅
通常,方法是不可等待的,类型是可等待的。如果希望能够编写类似于await MyMethod()
的内容,则MyMethod()
必须返回Task
、Task
或自定义await
able类型。使用自定义类型是一种罕见的高级场景;使用任务
,您有几个选项:
- 使用
和async
编写方法。这对于异步编写操作很有用,但不能用于最内部的wait
able调用wait
- 使用
上的方法之一创建Task
,如Task
或Task.Run()
Task.fromsync()
- 使用。这是最通用的方法,它可以用来从将来发生的任何事情中创建
able方法await
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
}
然后你可以声明你的[async方法],比如@Romiox
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));
}
异步任务foo1Async()
{
return wait Ext.ToTask(()=>foo1());
}
异步任务foo2Async(inti1)
{
return wait Ext.ToTask(()=>foo2(i1));
}
异步任务foo3Async()
{
return wait Ext.ToTask(()=>foo3());
}
异步任务foo4Async(inti1)
{
return wait Ext.ToTask(()=>foo4(i1));
}
或
异步任务foo1Async()
{
return wait Ext.ToTaskAsync(()=>foo1());
}
异步任务foo2Async(inti1)
{
return wait Ext.ToTaskAsync(()=>foo2(i1));
}
异步任务foo3Async()
{
return wait Ext.ToTaskAsync(()=>foo3());
}
异步任务foo4Async(inti1)
{
return wait Ext.ToTaskAsync(()=>foo4(i1));
}
现在您可以使用async并等待任何fooAsync方法,例如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;
}
异步任务TestAsync(){
///初始代码
int m=3;
///调用任务
var X=foo4Async(m);
///中间
///等我来的时候做点什么
///..
var结果=等待X;
///决赛
///这里有一些代码
返回结果;
}
如果您不想使用任务
,您可以编写一个完全定制的等待对象。这样的对象是一个实现方法GetAwaiter()
的对象,返回一个实现INotifyCompletion
的对象,该对象可以是对象本身
更多:
等待者实现:
是否获取状态IsCompleted
获取结果GetResult()
设置延续委托OnCompleted(动作延续)
Run
)
当然,也可以编写一个异步方法,返回
任务
或任务
。异步是很好的组合方式。我只是在学习C。我在使用GetStringAsync()查看同一个示例,尽管我是一名经验丰富的Java多线程程序开发人员,但我遇到了与OP完全相同的问题。这是一个很好的问题,可能应该在MSDN的文章中解决,否则这篇文章将非常完整。正确的是,创建一个可等待的方法最自然、最常用的方法是编写一个返回Task
或Task
的方法。但从技术上讲,如果YourOwnType
有一个名为GetAwaiter()
的公共无参数非静态实例方法,那么您也可以编写一个返回YourOwnType
的方法,该方法的返回类型是适当的(请在别处查找详细信息)。因此,await
有点像foreach
,它适用于任何具有合适公共方法的类型。很高兴知道!虽然它可能
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));
}
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));
}
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;
}
class Program {
// Need to change the declaration of Main() in order to use 'await'
static async Task Main () {
// Create a custom awaitable object
MyAwaitable awaitable = new MyAwaitable ();
// Run awaitable payload, ignore returned Task
_ = awaitable.Run ();
// Do some other tasks while awaitable is running
Console.WriteLine ("Waiting for completion...");
// Wait for completion
await awaitable;
Console.WriteLine ("The long operation is now complete. " + awaitable.GetResult());
}
}
public class MyAwaitable : INotifyCompletion {
// Fields
private Action continuation = null;
private string result = string.Empty;
// Make this class awaitable
public MyAwaitable GetAwaiter () { return this; }
// Implementation of INotifyCompletion for the self-awaiter
public bool IsCompleted { get; set; }
public string GetResult () { return result; }
public void OnCompleted (Action continuation) {
// Store continuation delegate
this.continuation = continuation;
Console.WriteLine ("Continuation set");
}
// Payload to run
public async Task Run () {
Console.WriteLine ("Computing result...");
// Wait 2 seconds
await Task.Delay (2000);
result = "The result is 10";
// Set completed
IsCompleted = true;
Console.WriteLine ("Result available");
// Continue with the continuation provided
continuation?.Invoke ();
}
}