当异步等待改变线程时?

15 浏览
0 Comments

当异步等待改变线程时?

当我调用test1()方法时,延迟1毫秒后ManagedThreadId会发生变化。

当我调用test2()方法(而不是test1())时,ManagedThreadId将保持不变。

异步等待何时改变线程?

在test2()方法中,完成方法所需的时间甚至比test1()还要长。

0
0 Comments

当async-await改变线程时,出现这个问题的原因是async-await关键字的行为。当使用await等待一个未完成的任务时,调用者的执行线程会发生变化。这是因为await会将后续的代码作为一个继续任务调度,而不是立即执行。

解决方法是根据任务是否已经完成来决定是否改变线程。如果任务已经完成,那么await会在当前线程上继续执行,不需要调度继续任务。如果任务未完成,那么await会将后续任务调度到其他线程上执行,直到任务完成。

这个问题的具体表现可以通过下面的例子来说明。在例子中,test1方法调用了一个异步操作Task.Delay(1),而test2方法调用了一个已经完成的任务Task.FromResult。当调用await test1()时,因为异步操作未完成,所以执行线程会改变。而当调用await test2()时,因为已经完成的任务,所以会在当前线程上同步执行。

这个问题可能会导致一些意外的结果。比如,在创建一个WPF窗口对象后,通过await Task.Delay(500)之后,会在一个不拥有该对象的新线程上执行,从而导致InvalidOperationException异常的发生。

需要注意的是,await会根据当前的同步上下文来调度后续任务的执行。在一些上下文中,比如WPF中的UI线程,会设置一个特定的同步上下文来调度UI相关的工作。如果将await配置为在默认上下文中运行,那么后续任务将在线程池线程上执行。

对于外部await和内部await之间是否会发生线程切换的问题,可以根据任务的完成情况进行推测。如果内部的await未完成,那么会发生线程切换。而外部的await是否发生线程切换,可能取决于具体的实现细节。

总之,当使用async-await时,并不会自动创建新线程。但是,当等待一个未完成的任务时,调用者的执行线程会发生变化。这一点需要注意,以避免出现意想不到的结果。

0