是否可以更改异步方法的任务创建选项?

时间:2017-10-30 23:28:23

标签: c# .net async-await

我有一个异步方法,我想给出TaskCreationOptions.LongRunning标志。使用包装Task

调用的非异步方法很容易
void Foo() { Thread.Sleep(5000); }
var task = Task.Factory.StartNew(Foo, TaskCreationOptions.LongRunning);
Console.WriteLine(task.CreationOptions);
// LongRunning

或许多变体中的任何一种(Task.Run,​​new Task等)。但是,似乎没有办法将方法定义为async并返回Task

async Task FooAsync() { await Task.Delay(TimeSpan.FromSeconds(10.0)); }
Task fooTask = FooAsync();
Console.WriteLine(FooTask.CreationOptions);
// None

尝试将其包装在长时间运行的任务中也是一个空启动:

async Task FooAsync() { await Task.Delay(TimeSpan.FromSeconds(10.0)); }
Task<Task> wrapTask = Task.Factory.StartNew(FooAsync, TaskCreationOptions.LongRunning);
Console.WriteLine(wrapTask.CreationOptions);
// LongRunning
Console.WriteLine(wrapTask.Unwrap().CreationOptions);
// None

在这种情况下,wrapTask确实是LongRunning,但它几乎立即返回(FooAsync调用await Task.Delay(...)后不久),因此设置该标志实际上可能不合需要。我最终想要等待的是wrapTask.Unwrap()

在我的测试中,我发现事实上,FooAsync中的代码在从await返回后在线程池线程中执行。按照正常情况,它在调用线程上调用,但之后不会尝试在调用线程上恢复执行。

我希望这可以通过方法属性来控制,但是我找不到任何可以帮助的方法。是否可以更改编译器为异步方法生成的创建选项?尝试是否有意义?

1 个答案:

答案 0 :(得分:7)

There Is No Thread

你的问题没有任何意义,因为async方法不是一个线程。它没有启动一个线程,它不代表一个线程,它没有任何与线程相关的有用方式。

async方法仅在等待其他异步操作的范围内是异步的。这就是全部。只有在那些操作作为实际线程(例如Task.Run())启动的情况下,甚至 一个线程才能描述为长时间运行,在这种情况下,您可以访问这些选项你想要,当你致电Task.Run()时。

如果您的async方法本身实际上是长期运行的,那么为什么要首先制作方法async?您可以在其他异步操作上使用同步等待来保持线程。恕我直言,这不是很理想,但是你已经接受了你会长时间坚持这个主题,所以为什么不更长?

或者,也许你只是意味着等待可能需要很长时间。在这种情况下,使用选项LongRunning甚至是不正确的,因为这告诉调度程序您的操作将持续一段时间的线程。您的投诉似乎是&#34;代码...在从await&#34; 返回后在线程池线程中执行。但是你的代码在等待期间实际上并没有持有一个帖子,所以它并没有真正长期运行。

如果您的方法元素实际运行了很长一段时间,然后通过await产生线程,并且您不想阻止当前线程其他等待的方法,然后在我看来你应该重构那些长期运行到他们自己的方法的async方法的部分,你可以通过{{1}执行}。然后你的Task.Run()方法可以等待那些没有阻塞当前线程的方法,你可以向线程调度程序指示操作的那些特定部分长时间运行(即将选项传递给async)。