1
21
你会遇到一些问题。调度器的饥饿避免机制将看到您的任务在等待进程时被阻塞。很难区分死锁线程和等待进程完成的线程。因此,如果任务运行或时间较长,它可能会安排新任务(请参见下文)。爬山启发式应该考虑到系统的整体负载,包括您的应用程序和其他应用程序的负载。它只是尝试最大化完成的工作,因此它将添加更多的工作,直到系统的总吞吐量停止增加,然后它将返回。我不 认为 这将影响您的申请,但滞育回避问题可能会。 你可以找到更多关于这一切如何运作的细节 Parallel Programming with Microsoft®.NET ,科林·坎贝尔,拉尔夫·约翰逊,艾德·米勒,斯蒂芬·图布(之前的草稿是 online ) “.NET线程池自动管理工作线程数 池中的线程。它根据内置的 试探法。.NET线程池有两种主要的注入机制 线程:一种避免饥饿的机制,增加了工人 线程如果在排队的项目和爬坡上看不到进展 尝试在使用as时最大化吞吐量的启发式方法 螺纹尽可能少。 避免饥饿的目标是防止僵局。这种 当工作线程等待同步时,可能会发生死锁。 只能由仍处于挂起状态的工作项满足的事件 在线程池全局或本地队列中。如果有固定的 工作线程的数量,所有这些线程都是类似的 如果被阻止,系统将无法取得进一步的进展。 添加新的工作线程可以解决问题。 爬山启发式的一个目标是提高利用率 当线程被I/O或其他等待条件阻塞时的核心数 这会使处理器停止工作。默认情况下,托管线程池有一个 每个芯的工作线程。如果这些工作线程中的一个 阻止,则有可能核心可能未被充分利用,具体取决于 在计算机上的总工作量。线程注入逻辑 不区分阻塞的线程和线程 这是一个漫长的,处理器密集型的操作。因此, 每当线程池全局或本地队列包含挂起时 工作项,运行时间较长的活动工作项(超过 半秒)可以触发创建新的线程池工作线程 线程。 .NET线程池有机会在 工作项完成的时间或以500毫秒的间隔,以两者中的哪一个为准 较短。线程池使用此机会尝试添加线程 (或将其带走),由之前在 线程计数。如果添加线程似乎有助于提高吞吐量, 线程池增加了更多;否则,它会减少 工作线程。这种技术被称为爬山启发式。 因此,缩短单个任务的一个原因是避免 饥饿检测,但另一个保持其简短的原因是 给线程池更多的机会通过 调整螺纹数量。个体持续时间越短 任务,线程池可以更频繁地测量吞吐量和 相应地调整线数。 为了具体化,考虑一个极端的例子。假设 您有一个复杂的财务模拟,需要500个处理器 操作,每个操作平均需要10分钟 完成。如果在全局队列中为每个 在这些操作中,大约五分钟后你会发现 线程池将增长到500个工作线程。原因是 线程池将所有任务视为已阻止,并开始添加新任务 线程的速率大约为每秒两个线程。 500个工作线程有什么问题?原则上,如果 你有500个核心供他们使用,还有大量的系统 记忆。实际上,这是并行计算的长期远景。 但是,如果您的计算机上没有那么多的核心,那么 在许多线程都在争夺时间片的情况下。这个 这种情况称为处理器过度订阅。允许许多 处理器密集型线程在单个核心上竞争时间增加 上下文切换开销,可严重减少整个系统 吞吐量。即使你没有用完内存,在这个性能 情况可能比顺序计算严重得多。 (每个上下文切换需要6000到8000个处理器周期。) 上下文切换的成本并不是开销的唯一来源。 .NET中的托管线程大约消耗1兆字节的堆栈 空间,无论该空间是否用于当前执行的函数。 创建新线程大约需要200000个CPU周期,并且 大约100000个周期使线程失效。这些是昂贵的操作。 只要你的任务不需要每分钟,线程池 爬山算法最终会发现它有太多的线程 自动削减开支。但是,如果您的任务 占用工作线程许多秒、分钟或小时,即 将抛出线程池启发式方法,此时您 应该考虑另一种选择。 第一种选择是将应用程序分解为较短的 任务的完成速度足以使线程池成功 控制线程数以获得最佳吞吐量。 第二种可能性是实现自己的任务调度程序 不执行线程注入的对象。如果你的任务很长 持续时间,您不需要高度优化的任务调度程序,因为 与执行相比,调度成本可以忽略不计。 任务的时间。msdn开发人员程序有一个示例 限制最大程度的简单任务调度程序实现 并发性。有关更多信息,请参阅章节,进一步阅读, 在本章末尾。 最后,您可以使用setmaxthreads方法 用数字的上限配置threadpool类 工作线程数,通常等于核心数(这是 environment.processorCount属性)。此上限适用于 整个过程,包括所有AppDomain。“ |
2
2
简短的回答是:不。
在内部,TPL使用标准
一旦外部流程准备就绪,是否可以让它们向您的应用程序报告?在这种情况下,您不必等待它们(保持线程被占用)。 |
3
-1
使用tpl/threadpool运行测试,以安排大量执行循环旋转的任务。使用外部应用程序,我已经使用proc affiliation将其中一个核心加载到100%。活动任务的数量从未减少。 更好的是,我运行了同一个CPU密集型.NET TPL应用程序的多个实例。所有应用程序的线程数都是相同的,并且从未低于内核数,即使我的机器几乎不能使用。 所以理论上,TPL使用可用的内核数量,但从不检查它们的实际负载。我认为这是一个非常糟糕的实施。 |
altwood · 任务未完成时[复制] 6 年前 |
SharmaPattar · 包含和不包含异步[重复]的任务返回类型 7 年前 |
Tobi · 聚合和连接(内部、外部、左侧,…)使用TPL数据流? 7 年前 |
nicks · 可以在不同的线程上等待任务完成吗?[副本] 7 年前 |