创建一个完成的任务


197

我要创建一个完成的Task(不是Task<T>)。.NET是否有内置的工具可以做到这一点?

一个相关的问题: 创建完成的Task <T>


2
It seems like the answer I'm getting from everyone is that using a garbage value like this is the correct way. That there isn't a way to do this without the garbage value is disappointing -- oh well.您认为这有什么问题?如果仅缓存一个,Task则整个程序将占用额外的一小部分内存。那是什么。同样,如果不这样做就可以创建完成的任务,这将再好不过了。
2013年

10
噢,我的失望与必须使用额外的内存无关。只是代码中任何地方的垃圾值都不优雅。
蒂莫西·希尔兹

1
请注意,今天有ValueTask完成的任务(例如,您已经拥有的值,因此代码本质上是同步的),这将节省您的分配。
nawfal

Answers:


246

.Net(v4.6)最新版本仅添加了一个内置Task.CompletedTask

Task completedTask = Task.CompletedTask;

该属性实现为无锁单例,因此您几乎总是使用相同的已完成任务。


1
刚刚检查了最新的VS 14 CTP并创建了一个4.5.3项目,Task.CompletedTask仍在内部。
彼得·里奇

1
2.您可能没有下载最新的CTP(4,并从该站点链接到该站点),或者您未指定版本4.5.3。这是我的机器上的东西。@PeterRitchie
i3arnon 2014年

我从Azure上的Visual Studio 14映像创建了VM。
彼得·里奇


我在使用Mono 5.4.1.7的Mac OS X上工作,但遇到了同样的错误。我怎样才能解决这个问题?
Khaled Annajar

152

Task<T>可以隐式转换为Task,因此只需获取一个完成的值Task<T>(具有T任意值)即可。您可以使用类似这样的东西来隐藏实际结果在某处的事实。

private static Task completedTask = Task.FromResult(false);
public static Task CompletedTask()
{
    return completedTask;
}

注意,由于我们不公开结果,并且任务总是完成的,因此我们可以缓存单个任务并重用它。

如果您使用的是.NET 4.0,FromResult则可以使用TaskCompletionSource以下方法创建自己的:

public static Task<T> FromResult<T>(T value)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(value);
    return tcs.Task;
}

8
如果您使用的是4.0,则可以添加Microsoft.Bcl.Async库以获取TaskEx.FromResult,以及其他方便的东西,例如WhenAll
Carl

@Servy从FromResult(false)和FromResult(true)会发生什么变化?
Francesco Bonizzi '16

3
@FrancescoB。如果您正在查看结果,那么它将更改结果的布尔值。如果您忽略结果,那么结果是无关紧要的。
Servy

66

我这样做的首选方法是不Task.WhenAll()带任何参数的调用。在MSDN文档指出:“如果所提供的阵列/枚举不包含任何任务,返回的任务将立即过渡到RanToCompletion状态之前它返回给调用者。” 这听起来像您想要的。

更新:我在Microsoft的参考源中找到了源;在那里,您可以看到Task.WhenAll包含以下内容:

return (tasks.Length == 0) ? // take shortcut if there are no tasks upon which to wait
            Task.CompletedTask :
            new WhenAllPromise(tasks);

因此Task.CompletedTask确实是内部的,但是通过不带任何参数的whenAll()公开它。


9
虽然确实有点古怪,但它得到了文档的支持,所以我不知道,我有点喜欢!
2016年

2
对我和我的.NET 4.5.2约束代码而言,它足够优雅。谢谢!
Stas Ivanov

36

我会用Task.Delay(0)。在内部,它返回complete的缓存实例Task<T>。无论如何,这正是当前答案所建议的方式,只是现在您不必自己缓存实例,也不在代码中有任何不雅观的垃圾值。

你可能会想,你可以使用Task.Yield(),而不是,但事实证明,结果Task.Yield()没有的一个亚型Task,而结果Task.Delay(0)是。这是两者之间的细微差别之一。


30

您可以使用Task.FromResult(在.NET 4.5中)返回completed Task<T>

如果您需要非泛型Task,则可以始终使用Task.FromResult(0)或类似Task<T>的类,因为它是的子类Task


11

适用于.Net 4.6及更高版本

return Task.CompletedTask;

对于较低版本,您可以使用

return new Task(() => { });

3
对于4.6之前的方法,请小心!您需要启动任务,否则它将永远无法完成!return Task.Delay(0);改为使用呢?
Miquel


0

怎么样:

#pragma warning disable 1998
    public async Task emptyTask() {
    }
#pragma warning restore 1998

如果您不介意,则可以省略警告抑制。


我相信标记方法async仍然可以创建整个状态机设备,即使您不使用它,因此对于资源不足的情况,返回空任务更为有效。
卡尔文·费舍尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.