如果我有一个类包含稍后要执行的任务队列,并且我有一个 async Task<T>
方法,如何在不执行该异步方法的情况下将其入队?
我想“延迟”这个任务,并确保调用者看到它稍后运行,就像在方法体中等待它一样。 --- 调用者不应该知道我已经将任务排入队列以备后用。
现在,如果我的队列已满,我将构造并返回一个新的 Task<T>
这里没有运行,返回 .Result
我的私有(private)异步方法:
public async Task<T> ExecuteAsync<T>(T transaction) {
if (mustDelay) {
Task<T> task = new Task<T>(t => executeAsync((T) t).Result, transaction);
enqueue(task);
return await task;
}
return await executeAsync(transaction);
}
private async Task<T> executeAsync<T>(T transaction) {
await someWork();
return transaction;
}
当其他一些任务完成时,我出列并 Start()
排队的任务:
dequeuedTask.Start();
这是否确保调用者看到与从方法返回等待结果相同的同步?
最佳答案
这是一个简化的例子:
async Task<T> GetResult<T>()
{
DoRightAway();
await DoLater();
return DoEvenLater();
}
Task<T> task = GetResult<T>();
//task is running or complete
您想推迟 GetResult<T>()
通过获取它代表的未完成任务来执行。问题是调用 async
方法开始运行它,即使你没有await
电话。该方法运行到第一个 await
,即 await DoLater()
在这个例子中。
了解为什么您无法获得 async
代表的任务方法而不运行它,请考虑以下三个概念:
- A
Func
对象表示未开始的计算。 - 一个新的
Lazy
对象表示将运行一次的未启动计算。 - 调用
async
方法代表最终的计算。
这些概念中的每一个都是不同的,但它们可以相互组合成组合表示。我们的GetResult<T>()
call 是第三个概念的一个例子。当结果准备好时,它将通过 await
继续执行。或 ContinueWith
.在我们的例子中,我们甚至不想开始执行。相反,我们需要将第一个和第三个概念组合成一个表示。也就是说,我们需要一个未启动计算(Func
),当它最终开始(async
方法调用)时,最终将完成。
将这种见解付诸实践,我们通过包装 GetResult<T>()
解决了我们的问题在 Func
中的 body .
Func<Task<T>> GetFactory()
{
return async () =>
{
DoRightAway();
await DoLater();
return DoEvenLater();
}
}
我们调用这个新方法来获取函数:
Func<Task<T>> function = GetFactory();
恭喜!我们没有运行就得到了任务!好吧,有点。我们有一个包装(尚未创建)任务的函数。当准备好创建和运行任务时,我们调用函数:
Task<T> task = function();
我们确保任务完成并获得结果:
T result = await task;
关于c# - 如何在不运行异步方法的情况下对异步方法的任务结果进行排队?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46896387/