[英]how can i force await to continue on the same thread?
await
does not guarantee continuation on the same task for spawned tasks: await
不保证在生成任务的同一任务上继续:
private void TestButton_Click(object sender, RoutedEventArgs e)
{
Task.Run(async () =>
{
Debug.WriteLine("running on task " + Task.CurrentId);
await Task.Delay(TimeSpan.FromMilliseconds(100));
Debug.WriteLine("running on task " + Task.CurrentId);
});
}
The output of this is: 这个输出是:
running on task 1
running on task
so we can see that not only the execution has moved to another task, but also to the UI-thread. 所以我们可以看到,不仅执行已经移动到另一个任务,而且还移动到UI线程。 How can i create a dedicated task, and enforce await to always continue on this task? 如何创建专用任务,并强制等待始终继续执行此任务? Long-running tasks don't do this either. 长时间运行的任务也不会这样做。
I have seen several SynchronizationContext implementations , but so far none of them worked, in this case because it uses threads and System.Threading.Thread is not available for uwp. 我已经看过几个SynchronizationContext实现 ,但到目前为止它们都没有工作,在这种情况下因为它使用线程而System.Threading.Thread不适用于uwp。
so we can see that not only the execution has moved to another task, but also to the UI-thread. 所以我们可以看到,不仅执行已经移动到另一个任务,而且还移动到UI线程。
No, it's not on the UI thread. 不,它不在UI线程上。 It's just technically not on a task, either. 从技术上讲,这也不是一项任务。 I explain why this happens in my blog post on Task.CurrentId
in async
methods . 我在async
方法的Task.CurrentId
博客文章中解释了为什么会发生这种情况。
How can i create a dedicated task, and enforce await to always continue on this task? 如何创建专用任务,并强制等待始终继续执行此任务? Long-running tasks don't do this either. 长时间运行的任务也不会这样做。
You're on the right track: you need a custom SynchronizationContext
(or a custom TaskScheduler
). 你走在正确的轨道上:你需要一个自定义的SynchronizationContext
(或一个自定义的TaskScheduler
)。
I have seen several SynchronizationContext implementations, but so far none of them worked, in this case because it uses threads and System.Threading.Thread is not available for uwp. 我已经看过几个SynchronizationContext实现,但到目前为止它们都没有工作,在这种情况下因为它使用线程而System.Threading.Thread不适用于uwp。
Try out mine . 试试我的 。 It should work on UWP 10.0. 它应该适用于UWP 10.0。
Don't use Task.Run
, just make the event handler async 不要使用Task.Run
,只需使事件处理程序异步
private async void TestButton_Click(object sender, RoutedEventArgs e)
{
await dedicated();
}
private async Task dedicated()
{
Console.WriteLine("running on task {0}", Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null");
await Task.Delay(TimeSpan.FromMilliseconds(100));
Console.WriteLine("running on task {0}", Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null");
}
Read more about Task.CurrentId
in Async Methods here : 在此处阅读有关Async方法中的Task.CurrentId
更多信息:
So
Task.CurrentId
returnsnull
because there is no task actually executing. 所以Task.CurrentId
返回null
因为没有任务实际执行。
The case with a thread pool thread is included in the link. 具有线程池线程的情况包含在链接中。 In particular look at this example 特别要看这个例子
static void Main(string[] args)
{
var task = Task.Run(() => MainAsync());
task.Wait();
taskRun = task.Id.ToString();
Console.WriteLine(beforeYield + "," + afterYield + "," + taskRun);
Console.ReadKey();
}
static async Task MainAsync()
{
beforeYield = Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null";
await Task.Yield();
afterYield = Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null";
}
Again, the clarification is 再一次,澄清是
the
null
comes into play because theasync
method is first executed as an actual task on the thread pool.null
发挥作用,因为async
方法首先作为线程池上的实际任务执行。 However, after itsawait
, it resumes as a regular delegate on the thread pool ( not an actual task ). 但是,在await
,它将恢复为线程池上的常规委托( 而不是实际任务 )。
This is an implementation detail of the async
call, I can only quote the link again: 这是async
调用的实现细节,我只能再次引用该链接:
It's likely that this behavior is just the result of the easiest and most efficient implementation. 这种行为可能只是最简单,最有效的实施的结果。
So you can't and you should not stop it from doing that, as far as a truly async
call is concerned. 因此,就真正的 async
调用而言,你不能也不应该阻止它这样做。
What you describe as the expected behavior instead is equivalent to a Task.Run
without await
您所描述的预期行为相当于没有 await
的Task.Run
private void expected()
{
Task task = Task.Run(() =>
{
Console.WriteLine("Before - running on task {0} {1}",
Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null",
Environment.CurrentManagedThreadId);
Task.Delay(TimeSpan.FromMilliseconds(100)).Wait();
Console.WriteLine("After - running on task {0} {1}",
Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null",
Environment.CurrentManagedThreadId);
});
}
Or a nested Task.Run
或嵌套的Task.Run
private void expected()
{
Task task = Task.Run(() =>
{
Console.WriteLine("Before - running on task {0} {1}",
Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null",
Environment.CurrentManagedThreadId);
var inner = Task.Run( async () =>
await Task.Delay(TimeSpan.FromMilliseconds(100)));
inner.Wait();
Console.WriteLine("After - running on task {0} {1}",
Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null",
Environment.CurrentManagedThreadId);
});
}
Output 产量
Before - running on task 312 11
After - running on task 312 11
Before - running on task 360 11
After - running on task 360 11
Before - running on task 403 15
After - running on task 403 15
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.