【发布时间】:2018-09-12 16:09:17
【问题描述】:
我正在构建相当复杂的并发系统并偶然发现了奇怪的问题。我会尽量简单。
- 我在 .net core 2.1 上有一个单实例控制台应用程序
- 我有一个 HttpClient 实例
- 我设置了以下参数: System.Net.ServicePointManager.DefaultConnectionLimit = int.MaxValue; System.Net.ServicePointManager.ReusePort = true; HttpClient.DefaultRequestHeaders.ConnectionClose = true; HttpClient.SetBearerToken(SOME_TOKEN);
- 我有一个线程 (A),它使用 ThreadPool/new Thread() 不断创建多达 30 个新的并发线程,并在内部使用单个 HTTP GET 查询(两者都试过了) 并将结果放入 ConcurrentQueue 变量中。
- 我有另一个线程 (B) 从队列中读取数据并不断创建多达 30 个新的并发线程,其中包含一个 HTTP POST 查询。
问题是我得到以下工作流程:
- A 线程运行良好,向队列提供结果。所有线程都运行良好。
- 在 A 线程启动之后,B 线程开始为 POST 创建子线程。
- A 线程完成了它的工作,所有线程都完成了。此时B线程创建的所有线程都挂在await client.PostAsync()方法上。
- 应用挂起大约 10 秒。
- VS 日志显示多个线程 0x35e0 已退出,代码为 0 (0x0)。 假定先前使用的线程正在释放的消息。为什么这么久?!
- 应用程序额外挂起 20 秒
- B 线程创建的第一个线程开始失败,然后所有其他 B 线程开始正常执行。
试过了:
一次将并发线程数减少到 5-10 可以解决问题,但会完全破坏并发性能。
我在日志中看到线程数并且没有溢出,A 和 B 一次最多 30 个线程(最多大约 60 个)
已尝试降低 System.Net.ServicePointManager.DefaultConnectionLimit 参数,但无济于事。
看起来有什么东西阻止了 POST 查询,然后他们又正常地冲了过来。请就这个问题提出建议。谢谢。
PS:我使用 Flickr 查询。会不会是他们的一些访问限制?无论如何,POST 挂起看起来很奇怪,它只是挂起而没有一次进入通行证。
【问题讨论】:
-
所以你可能有多达 60 多个线程?这听起来太多了,我希望这些线程之间的所有上下文切换都会影响性能。最好只使用 5 到 10 个线程,并了解和修复使用该线程数的缓慢性能。越多线程不一定越好!
-
可能是我对现代 PC 可以处理多少线程过于乐观,但 5-10 对我来说似乎是一个很低的数字。我希望我能得到更多,正如我所说的,它适用于 GET 查询线程。
-
现代 PC 可以处理大量线程,但不一定高效。您的 CPU 只能在物理上运行几个并发执行(取决于内核数量、共享资源的争用等);添加更多线程只会使性能变差,因为 CPU 必须在它们之间进行上下文切换,并且会增加资源争用。例如,B 线程长时间等待的设计对我来说似乎是可疑的——这些线程处于空闲状态,可能正在做其他有用的工作。
标签: c# .net multithreading concurrency .net-core