在处理任务时,经验法则似乎是线程池 - 通常由例如调用Task.Run()
或Parallel.Invoke()
- 应该用于相对较短的操作。在处理长时间运行的操作时,我们应该使用标志,以便 - 据我所知 - 避免堵塞线程池队列,即将工作推送到新创建的线程。何时应该将任务视为“长时间运行”?
但究竟是一个长时间运行操作? 就时间而言,漫长多久?在决定是否使用LongRunning
时,除了期望的任务持续时间之外是否还有其他因素需要考虑,如预期的CPU架构(频率,内核数量等)或将尝试执行的任务数量从程序员的角度立即运行?
例如,假设我有500个任务要在专用应用程序中处理,每个任务需要10-20秒才能完成。我是否应该使用Task.Run(例如,在一个循环中)启动所有500个任务,然后等待它们全部,也许是LongRunning
,而保留默认的最大并发级别?然后,如果在这种情况下设置了LongRunning
,那么与创建LongRunning
相比,这是否不会创建500个新线程,并且实际上会导致大量开销和更高的内存使用量(由于分配了额外的线程)?假设在这500个等待期间没有新任务将被安排执行。
我猜想决定设置LongRunning
取决于在给定的时间间隔内对线程池的请求数量,而LongRunning
应该只用于预计需要大大延长的任务线程池放置的任务 - 根据定义,最多只占所有任务的一小部分。换句话说,这似乎是一个排队和线程池利用率优化问题,应该可能通过测试逐案解决,如果有的话。我对么?
谢谢你的详细解答。是的,我正在承担CPU绑定任务。但是,在IO界限任务的情况下,为什么“LongRunning”与_parallelism_有什么关系? 'LongRunning = false'不会产生500个IO-bound任务,只是将它们放在线程池中(假设有足够的空间),而'LongRunning = true'会产生500个新线程 - 感知的并发性和响应性接近相同给用户,还是由于额外的线程创建开销在后一种情况下更糟? – w128
@ w128这是关于线程池如何分配新线程的。默认情况下,它根据CPU核心数量(通常约为物理核心数量的两倍)进行平衡,这对CPU的工作非常有用。当你需要*多*个线程时,线程池根据需要分配它们,但是延迟 - IIRC需要大约2s才能将新线程添加到池中。因此,如果一次向线程池添加500个阻塞任务,则池至少需要1000s才能拥有足够的线程来同时处理它们。 “LongRunning”只受旋转起来的限制,速度要快得多。 – Luaan