我如何强制等待在同一个线程上继续?

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.

回复评论

  1. "它仍然在 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).

  1. "我的问题是如何阻止它这样做"

这是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。