Math 编程逻辑-在线程之间拆分任务

Math 编程逻辑-在线程之间拆分任务,math,language-agnostic,programming-languages,multiprocessing,Math,Language Agnostic,Programming Languages,Multiprocessing,假设需要5个线程同时处理数据。同时假设您有89个任务要处理 一拍下来你就知道89/5=17,剩下的是4。分割任务的最佳方法是让4个(剩余的)线程分别处理18个(17+1)任务,然后让1个(#线程-剩余的)线程处理17个任务 这将消除剩余部分。只是为了验证: Thread 1: Tasks 1-18 (18 tasks) Thread 2: Tasks 19-36 (18 tasks) Thread 3: Tasks 37-54 (18 tasks) Thread 4: Tasks 55-

假设需要5个线程同时处理数据。同时假设您有89个任务要处理

一拍下来你就知道89/5=17,剩下的是4。分割任务的最佳方法是让4个(剩余的)线程分别处理18个(17+1)任务,然后让1个(#线程-剩余的)线程处理17个任务

这将消除剩余部分。只是为了验证:

Thread 1: Tasks  1-18  (18 tasks)
Thread 2: Tasks 19-36  (18 tasks)
Thread 3: Tasks 37-54  (18 tasks)
Thread 4: Tasks 55-72  (18 tasks)
Thread 5: Tasks 73-89  (17 tasks)
总共完成89项任务

我需要一种从数学上/可编程性上获得每个线程的开始和结束范围的方法;以下内容应与我上面列出的内容完全一致:

$NumTasks = 89
$NumThreads = 5
$Remainder = $NumTasks % $NumThreads 
$DefaultNumTasksAssigned = floor($NumTasks / $NumThreads)

For $i = 1 To $NumThreads
    if $i <= $Remainder Then
        $NumTasksAssigned = $DefaultNumTasksAssigned + 1
    else
        $NumTasksAssigned = $DefaultNumTasksAssigned
    endif
    $Start = ??????????
    $End = ??????????
    print Thread $i: Tasks $Start-$End ($NumTasksAssigned tasks)
Next
$NumTasks=89
$NumThreads=5
$余数=$NumTasks%$NumThreads
$defaultnumtaskssigned=floor($NumTasks/$NumThreads)
对于$i=1到$NumThreads

如果$i为什么?与其预先确定调度顺序,不如将所有任务都放在一个队列上,然后让每个线程在准备就绪时逐个将它们拉出。然后,您的任务基本上会“尽可能快地”运行

如果您预先分配了,那么一个线程可能正在执行特别长的一段时间的处理,并且阻塞了它后面的所有任务的运行。使用队列,随着每个任务的完成和线程的释放,它会抓取下一个任务并继续执行

把它想象成一家银行,每个出纳员一行,而不是一行和很多出纳员。在前一种情况下,你可能会被放硬币的人后面卡住,然后一个接一个地数出来,而在后一种情况下,你会找到下一个可用的出纳员,而PocketChange先生会一直数下去。

我支持哈东的说法。您可以一次只为他们提供一个任务(或者一次提供几个任务,具体取决于开销是否很大,即相对于启动/回收线程的成本而言,单个任务通常完成得非常快)。您随后的评论有效地解释了您的“线程”带来了沉重的创建成本,因此您希望用尽可能多的工作来满足他们的需求,而不是浪费时间创建新的“线程”,每个“线程”都需要少量的工作

无论如何。。。转到
数学问题

若您只想分配一次任务,请使用以下公式代替?????????按照您的逻辑,您应该做到以下几点:

$Start = 1 
         + (($i -1) * ($DefaultNumTasksAssigned + 1) 
        - (floor($i / ($Remainder + 1)) * ($i - $Remainder))
$End = $Start + $NumTasksAssigned -1
公式解释如下:
1表示您的显示/逻辑是基于一而不是基于零的事实
第二个术语是因为我们通常在每次迭代中添加($DefaultNumtasksSigned+1)。
第三项为最后几次迭代提供了修正。
它的第一部分,
(floor($i/($restinutes+1))
提供0,直到$i到达第一个线程
不会收到一个额外任务,之后会收到一个。
第二部分表示我们需要纠正的程度。

$End的公式更简单,唯一的技巧是-1,这是因为起始值和结束值都包含在内(例如,在1到19之间有19个任务,而不是18个任务)

下面稍加修改的逻辑也应该起作用,它通过保留$Start变量的一个运行选项卡,而不是每次重新计算,从而避免了“花哨”公式

$NumTasks = 89
$NumThreads = 5
$Remainder = $NumTasks % $NumThreads 
$DefaultNumTasksAssigned = floor($NumTasks / $NumThreads)
$Start = 1
For $i = 1 To $NumThreads
    if $i <= $Remainder Then    // fixed here!  need <= because $i is one-based
        $NumTasksAssigned = $DefaultNumTasksAssigned + 1
    else
        $NumTasksAssigned = $DefaultNumTasksAssigned
    endif
    $End = $Start + $NumTasksAssigned -1
    print Thread $i: Tasks $Start-$End ($NumTasksAssigned tasks)

    $Start = $Start + $NumTasksAssigned
Next
$NumTasks=89
$NumThreads=5
$余数=$NumTasks%$NumThreads
$defaultnumtaskssigned=floor($NumTasks/$NumThreads)
$Start=1
对于$i=1到$NumThreads
如果$i我想你已经

事实上,要准确确定完成所有任务所需的时间几乎是不可能的,除非以下所有条件都是正确的:

  • 您的任务是100%CPU限制的:也就是说,它们在运行时使用100%的CPU,不需要做任何I/O
  • 您的任何任务都不必以任何方式与任何其他任务同步
  • 线程的数量与CPU的数量完全相同
  • 运行这些任务的计算机没有同时执行任何其他有趣的任务
实际上,大多数情况下,您的任务都是I/O绑定的,而不是CPU绑定的:也就是说,您正在等待一些外部资源,例如从文件读取、从数据库获取或与远程计算机通信。在这种情况下,添加更多线程只会使情况变得更糟,因为它们都在争夺相同的资源来源

最后,除非你有一些非常奇怪的硬件,否则你不可能有五个线程同时运行。(通常处理器配置是至少两个线程的倍数。)通常,如果您的任务非常受CPU限制,那么最佳点是每个CPU大约1个线程;如果任务将一半时间用于CPU限制,一半时间用于IO,那么最佳点是每个CPU大约2个线程,等等


tl;dr:我们需要更多地了解您的任务和硬件外观,然后才能就此问题向您提供建议。

我使用的语言实际上不支持真正的多线程,而是支持并行处理。这里的想法是尽可能长时间地“保持”进程,因为“释放”一个是关闭一个进程,另一个是打开的,这比处理本身需要更多的时间。我的方法是让5个并发进程在大部分时间内运行,每个进程同时处理自己的小任务。@BHare:那你为什么要标记这个问题
c
php
?这很好,但如果你已经共享了对资源的访问,将共享队列用作任务源和预先分配的列表之间没有区别。当然,队列将添加某种类型的同步(但这可能不是问题,取决于您的多任务)。没有对资源的共享访问,“并行处理”这真的是一个不受支持的黑客让它工作。我可以使用进程间通信,但这有点过头了。这将简单地向进程发送指令(进程任务x-y)并从这一点开始
>>> def ShowWorkAllocation(NumTasks, NumThreads):
...   Remainder = NumTasks % NumThreads
...   DefaultNumTasksAssigned = math.floor(NumTasks / NumThreads)
...   Start = 1
...   for i in range(1, NumThreads + 1):
...     if i <= Remainder:
...        NumTasksAssigned = DefaultNumTasksAssigned + 1
...     else:
...        NumTasksAssigned = DefaultNumTasksAssigned
...     End = Start + NumTasksAssigned - 1
...     print("Thread ", i, ": Tasks ", Start, "-", End, "(", NumTasksAssigned,")")
...     Start = Start + NumTasksAssigned
...
>>>
>>> ShowWorkAllocation(89, 5)
Thread  1 : Tasks  1 - 18 ( 18 )
Thread  2 : Tasks  19 - 36 ( 18 )
Thread  3 : Tasks  37 - 54 ( 18 )
Thread  4 : Tasks  55 - 72 ( 18 )
Thread  5 : Tasks  73 - 89 ( 17 )

>>> ShowWorkAllocation(11, 5)
Thread  1 : Tasks  1 - 3 ( 3 )
Thread  2 : Tasks  4 - 5 ( 2 )
Thread  3 : Tasks  6 - 7 ( 2 )
Thread  4 : Tasks  8 - 9 ( 2 )
Thread  5 : Tasks  10 - 11 ( 2 )
>>>

>>> ShowWorkAllocation(89, 11)
Thread  1 : Tasks  1 - 9 ( 9 )
Thread  2 : Tasks  10 - 17 ( 8 )
Thread  3 : Tasks  18 - 25 ( 8 )
Thread  4 : Tasks  26 - 33 ( 8 )
Thread  5 : Tasks  34 - 41 ( 8 )
Thread  6 : Tasks  42 - 49 ( 8 )
Thread  7 : Tasks  50 - 57 ( 8 )
Thread  8 : Tasks  58 - 65 ( 8 )
Thread  9 : Tasks  66 - 73 ( 8 )
Thread  10 : Tasks  74 - 81 ( 8 )
Thread  11 : Tasks  82 - 89 ( 8 )
>>>