我如何强制等待在同一个线程上继续?
how can i force await to continue on the same thread?
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线程。我如何创建一个专门的任务,并强制等待总是继续这个任务? Long-运行 任务也不会这样做。
我见过几个 SynchronizationContext implementations,但到目前为止 none 有效,在这种情况下是因为它使用线程并且 System.Threading.Thread 不适用于 uwp。
不要使用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");
}
在异步方法中阅读有关 Task.CurrentId
的更多信息 here:
So Task.CurrentId
returns null
because there is no task actually
executing.
回复评论
- "它仍然在 UI 线程上运行,而不是衍生任务。"
带有线程池线程的情况包含在link中。特别看看这个例子
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";
}
再次澄清
the null
comes into play because the async
method is first executed as
an actual task on the thread pool. However, after its await
, it
resumes as a regular delegate on the thread pool (not an actual task).
- "我的问题是如何阻止它这样做"
这是async
调用的实现细节,我只能再次引用link:
It’s likely that this behavior is just the result of the easiest and
most efficient implementation.
所以就 真正 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
so we can see that not only the execution has moved to another task, but also to the UI-thread.
不,它不在 UI 线程中。从技术上讲,这也不是一项任务。我在 Task.CurrentId
in async
methods.
上的博客 post 中解释了为什么会发生这种情况
How can i create a dedicated task, and enforce await to always continue on this task? Long-running tasks don't do this either.
您走在正确的轨道上:您需要定制 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.
试试看 mine。它应该适用于 UWP 10.0。
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线程。我如何创建一个专门的任务,并强制等待总是继续这个任务? Long-运行 任务也不会这样做。
我见过几个 SynchronizationContext implementations,但到目前为止 none 有效,在这种情况下是因为它使用线程并且 System.Threading.Thread 不适用于 uwp。
不要使用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");
}
在异步方法中阅读有关 Task.CurrentId
的更多信息 here:
So
Task.CurrentId
returnsnull
because there is no task actually executing.
回复评论
- "它仍然在 UI 线程上运行,而不是衍生任务。"
带有线程池线程的情况包含在link中。特别看看这个例子
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";
}
再次澄清
the
null
comes into play because theasync
method is first executed as an actual task on the thread pool. However, after itsawait
, it resumes as a regular delegate on the thread pool (not an actual task).
- "我的问题是如何阻止它这样做"
这是async
调用的实现细节,我只能再次引用link:
It’s likely that this behavior is just the result of the easiest and most efficient implementation.
所以就 真正 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
so we can see that not only the execution has moved to another task, but also to the UI-thread.
不,它不在 UI 线程中。从技术上讲,这也不是一项任务。我在 Task.CurrentId
in async
methods.
How can i create a dedicated task, and enforce await to always continue on this task? Long-running tasks don't do this either.
您走在正确的轨道上:您需要定制 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.
试试看 mine。它应该适用于 UWP 10.0。