首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往
您找到你想要的搜索结果了吗?
是的
没有找到

使用 Task.Wait()?立刻死锁(deadlock)

明确了会造成死锁的条件和不会造成死锁的条件后,我们只需要做到以下几点即可避免死锁了: 在 UI 线程,如果使用了 async/await,就尽量不要再使用 Task.Wait()/Task.Result...如果可能,尽量在异步任务后添加 .ConfigureAwait(false);这样,异步任务后面继续执行的代码就不会回到原 UI 线程了,而是直接从线程池中再取出一个线程执行;这样,即便 UI 线程后续可能有别的原因造成阻塞...: async Task DoAsync() { await Task.Run(() => { }).ConfigureAwait(false); } 这样,即便真的使用 DoAsync().Wait...注意,整个方法调用链都需要使用 .ConfigureAwait(false) 才能够防止线程切换时,在调用方的 Wait() 方法中发生死锁。...详见我的另一篇博客 在编写异步方法时,使用 ConfigureAwait(false) 避免使用者死锁。)

1.2K10

探究C#的Task中ConfigureAwait方法

ConfigureAwait方法的使用场景 非UI线程场景 在非UI线程中执行任务时,可以使用ConfigureAwait(false)来告知任务在执行期间不需要同步回原始上下文。...(false); // 继续在非UI线程中执行其他逻辑 } 避免上下文切换 在高并发场景下,如果任务不需要访问UI线程同步上下文,可以使用ConfigureAwait(false...UI线程中执行其他逻辑 } 避免死锁 在某些特定场景下,如果任务中存在等待同步资源的操作,而同步资源又由UI线程进行访问,此时使用ConfigureAwait(false)可以避免发生死锁情况...(false); // 继续在非UI线程中执行其他逻辑 await Task.Delay(1000); // 等待同步资源 } ConfigureAwait方法的注意事项 在UI线程使用时需要小心...因此,在UI线程使用ConfigureAwait(false)时需要特别小心。

53820

.NET 探究Task中ConfigureAwait方法

ConfigureAwait方法的使用场景 非UI线程场景 在非UI线程中执行任务时,可以使用ConfigureAwait(false)来告知任务在执行期间不需要同步回原始上下文。...(false); // 继续在非UI线程中执行其他逻辑 } 避免上下文切换 在高并发场景下,如果任务不需要访问UI线程同步上下文,可以使用ConfigureAwait(false)来避免不必要的上下文切换...UI线程中执行其他逻辑 } 避免死锁 在某些特定场景下,如果任务中存在等待同步资源的操作,而同步资源又由UI线程进行访问,此时使用ConfigureAwait(false)可以避免发生死锁情况。...(false); // 继续在非UI线程中执行其他逻辑 await Task.Delay(1000); // 等待同步资源 } ConfigureAwait方法的注意事项 在UI线程使用时需要小心...因此,在UI线程使用ConfigureAwait(false)时需要特别小心。

19920

浅谈Await

await使得我们使用异步更加时特别便捷,并且还不会导致线程堵塞。我们在使用时也就莫名其妙的使用。往往不知道为什么不会导致线程堵塞。在这里,简单的谈论下await的一点原理。      ...,也就是弹出"同步代码"这句话,直到await等待子线程执行完毕后执行主线程睡眠那句代码,也就是主线程阻塞3秒钟.  2.ConfigureAwait方法    在Task里中有ConfigureAwait...这个上下文一般时UI上下文(运行在UI上)请求上下文(ASP.NET) 这两个可以说时原始上下文,而其它情况采用线程池上下文,也就是开辟一个新线程。...//将后续代码交给线程池执行 await Task.Run(() => { Thread.Sleep(3000); }).ConfigureAwait(false);...Thread.Sleep(3000); } 我们使用ConfigureAwait将后续代码交给线程池来执行,也就是下面的Thread.Sleep并不会阻塞窗体.运行后发现结果也是如我们所想

1.1K20

c#异步编程-Task(二)

“抢占” 的时刻就是在await期间 这种并发发生在调用栈较浅的地方(Task.Run调用的代码里) 为了从该模型获益,真正的并发代码要避免访问共享状态UI控件。...Task,就可以避免此类错误的发生: Task valueTask = Foo().AsTask(); 避免过度的弹回 对于在循环中多次调用的方法,通过调用ConfigureAwait方法,就可以避免重复的弹回到...(false); } } async Task C() { ... } 这意味着对于方法B和C,我们取消了UI线程中简单线程安全模型,即代码在UI线程上运行,并且只能在await语句期间被抢占...编译器的异步函数生成的Task在遇到未处理的OperationCanceledException异常时会自动进入取消状态(IsCanceled返回true,IsFaulted返回false使用Task.Run...因为这可能是一个库方法,无需与外界共享状态,所以在await时我们使用ConfigureAwaitfalse)来避免弹回到UI的同步上下文。

2.5K30

ConfigureAwait in .NET 8

使用 ConfigureAwait(false) 时,异步方法会在任何可用的线程线程上恢复。 ConfigureAwait(false) 的历史很有趣(至少对我来说是这样)。...既然谈到了 ConfigureAwait(false),我想指出几个常见的误解: 1、ConfigureAwait(false) 并不是避免死锁的好方法。...为了在直接阻塞避免死锁,你必须确保所有异步代码都使用 ConfigureAwait(false),包括库和运行时中的代码。这并不是一个非常容易维护的解决方案。还有更好的解决方案。...3、ConfigureAwait(false) 并不意味着”在线程线程上运行此方法的后续部分“”在不同的线程上运行此方法的后续部分“。它只在 await 暂停执行并稍后恢复异步方法时生效。...Task task = Task.Run(() => throw new InvalidOperationException()); // 同步阻塞任务(不推荐)。不会抛出异常。

21010

使用异步操作时的注意要点(翻译)

,使用Task,FromResult要比Task.Run性能要好,因为Task.FromResult只是创建了一个包装已计算任务的任务,而Task.Run会将一个工作项在线程池进行排队,计算,返回.并且使用...或者处理某些数据,此类线程不建议使用Task.Run方法执行,因为Task.Run方法是将任务在线程池内进行排队执行,如果线程线程进行长时间堵塞,会导致线程池增长,进而浪费性能,所以如果想要运行长时间的工作建议直接创建一个新线程进行工作...异步线程启动 2.调用线程调用Result或者Wait()进行阻塞 3.异步完成时,将一个延续代码调度到线程池,恢复等待该操作的代码 虽然看起来并没有什么关系,但是其实这里却是使用了两个线程来完成同步操作...UI线程调用 // Result和Wait()方法如果出现异常,异常将被包装为AggregateException进行抛出, return Task.Run(() => RunAsync...,Stream和StreamWriter将使用同步的方式进行write/flush,这将会导致线程阻塞,并且有可能导致线程池内线程不足(线程池饥饿) ❌下面例子由于没有调用FlushAsync(),所以最后是以同步方式进行

4.6K20

C#并发编程之异步编程(三)

UI应用程序里,比如ASP.NET或者WinForm程序里,你的代码会在ASP.NET工作线程WinForm工作线程上运行。...但是如果使用Task.Run,那么执行该任务时就要用到线程池里的线程了。 那么问题来了,我们在编写异步方法的时候,确确实实可以看到这个方法被执行了,肯定有线程执行才行啊。...为了避免这种开销,.NET内部也是有自己的优化机制的,它会在捕获的SynchronizationContext与任务完成时的当前上下文相同时,不使用POST。...1: byte[] bytes = await httpClient.PostAsJsonAsync(url,data).ConfigureAwait(false).ReadAsStreamAsync...解决问题的方法就是,我们可以使用线程线程来解决这个问题。如以下代码: 1: var result = Task.Run(() =>GetUserAsync()).Result;

1.4K50

C#异步使用要点(翻译)

,使用Task,FromResult要比Task.Run性能要好,因为Task.FromResult只是创建了一个包装已计算任务的任务,而Task.Run会将一个工作项在线程池进行排队,计算,返回.并且使用...,此类线程不建议使用Task.Run方法执行,因为Task.Run方法是将任务在线程池内进行排队执行,如果线程线程进行长时间堵塞,会导致线程池增长,进而浪费性能,所以如果想要运行长时间的工作建议直接创建一个新线程进行工作...和Task.Wait()来堵塞线程 使用Task.Result和Task.Wait()两个方法进行阻塞异步同步化比直接同步方法阻塞还要MUCH worse(更糟),这种方式被称为Sync over async...UI线程调用 // Result和Wait()方法如果出现异常,异常将被包装为AggregateException进行抛出, return Task.Run(() => RunAsync...,Stream和StreamWriter将使用同步的方式进行write/flush,这将会导致线程阻塞,并且有可能导致线程池内线程不足(线程池饥饿) 下面例子由于没有调用FlushAsync(),所以最后是以同步方式进行

3.3K50

不要使用 Dispatcher.Invoke,因为它可能在你的延迟初始化 Lazy 中导致死锁

WPF 中为了 UI 的跨线程访问,提供了 Dispatcher 线程模型。其 Invoke 方法,无论在哪个线程调用,都可以让传入的方法回到 UI 线程。...此死锁的原因 后台线程访问到 Lazy,于是 Lazy 内部获得同步锁; 主 UI 线程访问到 Lazy,于是主 UI 线程等待同步锁完成,并进入阻塞状态(以至于不能处理消息循环); 后台线程的初始化调用到...Invoke 需要到 UI 线程完成指定的任务后才会返回,但 UI 线程此时阻塞不能处理消息循环,以至于无法完成 Invoke 内的任务; 于是,后台线程在等待 UI 线程处理消息以便让 Invoke...所以,这段初始化代码既然不可避免地会并发,那么就应该阻止并发造成的死锁问题。也就是不要使用 Invoke 而是改用 InvokeAsync。...,使用 ConfigureAwait(false) 避免使用者死锁 - walterlv 将 async/await 异步代码转换为安全的不会死锁的同步代码(使用 PushFrame) - walterlv

27420

C# 高级:TAP 异步编程

解决此类问题需要使用异步编程,异步强调的是非阻塞,是一种编程模式,主要解决了因文件、网络等 I/O 操作阻塞线程工作的问题,比如阻塞期间 UI 无法响应问题。 而异步编程又可以借助多线程技术来解决。...在等待 I/O 请求时让出线程使其继续进行 UI 交互,并将需要长时间运行的工作过渡到其他 CPU 线程使用户界面的响应性更强。...原因是 UI线程执行到这句代码时,就开始等待异步任务的结果,处于阻塞状态。...ConfigureAwait(false) 的作用是告诉主线程,我要去远行了,你去做其它事情吧,不用等我。只要先确保一方不在一直等另一方,就能避免互相等待而造成死锁的情况。...它使我们可以只关注业务层面要处理的任务,而不必关心和使用线程线程池。重要的是要把 Task 理解为发起异步工作的抽象,而不是对线程的抽象。

97220

在有 UI 线程参与的同步锁(如 AutoResetEvent)内部使用 await 可能导致死锁

} finally { // 释放锁 } 我们设置了线程池最小线程数为 100,这样在使用 Task.Run 进行并发的时候,一次能够开启 100 个线程来执行 Do 方法。...此死锁的触发条件 实际上,以上这段代码如果没有 WPF / UWP 的 UI 线程的参与,是 不会出现死锁 的。 但是,如果有 UI 线程参与,即便只有 UI 线程调用,也会直接死锁。...此死锁的原因 WPF / UWP 等 UI 线程使用 DispatcherSynchronizationContext 作为线程同步上下文,我在 出让执行权:Task.Yield, Dispatcher.Yield...,使用 ConfigureAwait(false) 避免使用者死锁 - walterlv 将 async/await 异步代码转换为安全的不会死锁的同步代码(使用 PushFrame) - walterlv...本文会经常更新,请阅读原文: https://blog.walterlv.com/post/deadlock-if-await-in-ui-lock-context.html ,以避免陈旧错误知识的误导

17040

看过这么多爆文,依旧走不好异步编程这条路?​

大家都知道:WinForm和WPF都有类似的原则:长耗时的任务在后台进行,将异步结果返回给UI线程 。(这难道就是ConfigureAwait方法默认传true的原因?)...因此,对于ASP.NET Core程序,ConfigureAwait(false)不是必需的,然而,在基础库时最好还是使用ConfigureAwait(false),因为你保不准上层会混用同步/异步代码...引言代码为什么发生deadlock 观察引言代码,控制权返回到上层调用函数时,执行流使用Result/(Wait方法)等待任务结果:Result/Wait()导致调用线程同步阻塞(等待任务完成), 而异步任务执行完成后...正因为如此,我们提出两种方式解决死锁: 原调用函数始终使用await方法,这样调用线程是异步等待任务完成,后继代码可以在该线程同步上下文上执行 对异步任务应用ConfigureAwait(false)方法...ConfigureAwait(false) 能解决[因调用线程同步阻塞]引发的死锁,但是同步阻塞没有利用异步编程的优点,不是很推荐。

80320

16:几个常见的TAP异步操作

FindFilesAsync( string pattern, IProgress>>> progress) 使用...原因是 UI线程执行到这句代码时,就开始等待异步任务的结果,处于阻塞状态。...而异步任务执行完后回来准备找 UI 线程继续执行后面的代码时,却发现 UI 线程一直处于“忙碌”的状态,没空搭理回来的异步任务。这就造成了你等我,我又在等你的尴尬局面。...(false); } } 虽然两种方法都可行,但如果作为异步方法提供者,比如封装一个通用库时,考虑到难免会有新手开发者会使用 CurlAsync().Result,为了提高通用库的容错性,我们就可能需要使用...ConfigureAwait(false) 的作用是告诉主线程,我要去远行了,你去做其它事情吧,不用等我。只要先确保一方不在一直等另一方,就能避免互相等待而造成死锁的情况。

76510
领券