我有一个异步方法,我想给出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
返回后在线程池线程中执行。按照正常情况,它在调用线程上调用,但之后不会尝试在调用线程上恢复执行。
我希望这可以通过方法属性来控制,但是我找不到任何可以帮助的方法。是否可以更改编译器为异步方法生成的创建选项?尝试是否有意义?
答案 0 :(得分:7)
你的问题没有任何意义,因为async
方法不是一个线程。它没有启动一个线程,它不代表一个线程,它没有任何与线程相关的有用方式。
async
方法仅在等待其他异步操作的范围内是异步的。这就是全部。只有在那些操作作为实际线程(例如Task.Run()
)启动的情况下,甚至 一个线程才能描述为长时间运行,在这种情况下,您可以访问这些选项你想要,当你致电Task.Run()
时。
如果您的async
方法本身实际上是长期运行的,那么为什么要首先制作方法async
?您可以在其他异步操作上使用同步等待来保持线程。恕我直言,这不是很理想,但是你已经接受了你会长时间坚持这个主题,所以为什么不更长?
或者,也许你只是意味着等待可能需要很长时间。在这种情况下,使用选项LongRunning
甚至是不正确的,因为这告诉调度程序您的操作将持续一段时间的线程。您的投诉似乎是&#34;代码...在从await
&#34; 返回后在线程池线程中执行。但是你的代码在等待期间实际上并没有持有一个帖子,所以它并没有真正长期运行。
如果您的方法元素做实际运行了很长一段时间,然后通过await
产生线程,并且您不想阻止当前线程其他等待的方法,然后在我看来你应该重构那些长期运行到他们自己的方法的async
方法的部分,你可以通过{{1}执行}。然后你的Task.Run()
方法可以等待那些没有阻塞当前线程的方法,和你可以向线程调度程序指示操作的那些特定部分长时间运行(即将选项传递给async
)。