【问题标题】:Informing ThreadPool.QueueUserWorkItem about memory requirements通知 ThreadPool.QueueUserWorkItem 内存需求
【发布时间】:2023-04-06 09:15:01
【问题描述】:

我们正在设计一个应用程序,用户可以在其中设置同时运行的多个任务。我们使用 ThreadPool.QueueUserWorkItem 来设置任务运行。那部分运行良好。

我们确实有一个问题,这些任务可能会消耗 500MB 以上的内存。我们使用内存映射 I/O 来管理内存。仍然当用户设置 10+ 个任务同时运行时,线程池将启动所有这些任务,并且有时我们会耗尽内存并发生异常。我们可以很好地处理错误。

我想知道是否有办法在处理队列时考虑将消耗的内存,即保持任务排队直到存在足够的内存?我可以告诉线程池我们将要求多少内存(我们可以粗略估计)吗?

【问题讨论】:

  • 听起来根本不像适当地使用线程池。 TP 线程应该只执行短时间的小部分工作,不超过半秒。使用有限数量的 Thread 对象,不超过 Environment.ProcessorCount 和一个线程安全队列来让它们工作。
  • 谢谢,我想我们会用这种方法编写自己的池。

标签: .net multithreading memory threadpool queueuserworkitem


【解决方案1】:

ThreadPool 对您在任务中执行的操作一无所知。您需要自己确保这一点。您可以管理一个 long 类型的全局变量,该变量表示所有正在运行的作业在峰值时可能需要的总字节数。当线程池调度您的一项任务时,您首先检查该变量。 如果它已经太高,请等到当前正在运行的任何任务退出。然后再次检查。

对此的低技术解决方案是使用具有 100 毫秒睡眠间隔的轮询。高科技版本会使用某种涉及事件的等待方案。

【讨论】:

    【解决方案2】:

    好的,如果您可以获得每个任务的内存估计值,您可以通过在池中保留一个粗略的受 CS 保护的内存使用计数来做到这一点。在提交任务之前添加到这个计数,并让任务调用“memRelease”函数在它结束之前从它减去,然后检查现在是否可以运行任何东西,(见下文)。

    如果某个线程想要提交任务并且发现(通过将其需求与 CS 中的当前使用情况进行比较),“预算”中剩余的内存不足来运行它,您可以将其推入一个并发队列/列表等待直到有。每当任务完成并调用“memRelease”时,它就会添加到内存 buget 并迭代队列/列表(首先锁定它),以尝试找到现在可以在增加的可用内存下运行的东西。如果是,它会将任务提交到池中。

    【讨论】:

    • 可能存在一些问题 - 负载过重的系统可能会通过不断加载具有较小需求的新到达任务来锁定高内存需求的任务。应用某种反饥饿算法是可能的,也许通过在添加任务时迭代“待处理”列表来决定是提交新任务还是将其添加到待处理列表的末尾以允许足够的内存建立运行一些需要大量且已等待很长时间的待处理任务。
    【解决方案3】:

    您可以通过 ThreadPool.SetMaxThreads 控制线程池中的线程数。所以你可以做的是设置你的最大线程数

    ThreadPool.SetMaxThreads = new PerformanceCounter("Memory", "Available MBytes").RawValue / 500;
    

    PerformanceCounter("Memory", "Available MBytes").RawValue -> 以 MB 为单位返回可用内存

    【讨论】:

    • 这是一个进程全局设置。你绝对不应该这样做。不要用本地解决方案解决本地问题。它也不能解决问题,因为作业有不同的内存要求。找不到静态的最大线程数。
    猜你喜欢
    • 2011-02-11
    • 2017-04-09
    • 2016-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-28
    • 1970-01-01
    相关资源
    最近更新 更多