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);
});
}
这个输出是:
running on task 1
running on task
所以我们可以看到,不仅执行已经移动到另一个任务,而且还移动到UI线程。如何创建专用任务,并强制等待始终继续执行此任务?长时间运行的任务也不会这样做。
我见过几个SynchronizationContext implementations,但到目前为止它们都没有用,在这种情况下因为它使用线程而且System.Threading.Thread不适用于uwp。
答案 0 :(得分:9)
所以我们可以看到,不仅执行已经移动到另一个任务,而且还移动到UI线程。
不,它不在UI线程上。它在技术上也不是一项任务。我在Task.CurrentId
in async
methods的博文中解释了为什么会这样。
如何创建专用任务,并强制等待始终继续执行此任务?长期执行的任务也不会这样做。
您已走上正轨:您需要自定义SynchronizationContext
(或自定义TaskScheduler
)。
我已经看过几个SynchronizationContext实现,但到目前为止它们都没有工作,在这种情况下因为它使用线程而且System.Threading.Thread不适用于uwp。
试试mine。它应该适用于UWP 10.0。
答案 1 :(得分:2)
不要使用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");
}
详细了解异步方法here中的Task.CurrentId
:
所以
Task.CurrentId
返回null
,因为实际上没有任务 执行。
链接中包含线程池线程的情况。特别要看这个例子
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";
}
同样,澄清是
null
开始发挥作用,因为async
方法首先被执行为 线程池上的实际任务。但是,在它await
之后 恢复为线程池中的常规委托(不是实际任务)。
这是async
电话的实施细节,我只能再次引用该链接:
这种行为很可能只是最简单的结果 最有效的实施。
所以,就真正的 async
电话而言,你不能也不应该阻止它这样做。
您所描述的预期行为相当于Task.Run
没有 await
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);
});
}
或嵌套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);
});
}
输出
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