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

时间:2011-06-18 00:49:07

标签: math language-agnostic programming-languages multiprocessing

假设您希望5个线程同时处理数据。还假设您有89个要处理的任务。

击球你知道89/5 = 17,剩下的4分。任务拆分的最佳方法是让4个(余数)线程分别处理18(17 + 1)个任务,然后得1( #threads - remainder)线程处理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

注意:请坚持回答手头的数学,避免暗示或假设情况。

3 个答案:

答案 0 :(得分:7)

为什么呢?而不是预先确定调度顺序,将所有任务粘贴在队列上,然后让每个线程在准备好时逐个拉出它们。然后你的任务基本上会“尽可能快地”运行。

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

把它想象成一个银行,每个柜员一行,一行和很多出纳员。在前者中,你可能会被困在存放硬币的人身后并逐一计算出来,后者你会到达下一个可用的出纳员,而PocketChange先生则计算在内。

答案 1 :(得分:1)

我是哈顿的第二句话。您可以一次向它们提供一个任务(或者一次一个地执行一些任务,具体取决于是否有很多开销,即相对于启动/回收线程的成本,单个任务通常非常快地完成)。 em>您的后续评论有效地解释了您的“线程”带来了巨大的创作成本,因此您希望尽可能多地提供一次工作,而不是浪费时间创建新的“线程”,每个人都提供少量工作。

无论如何......转到math question ...

如果您只想分配一次任务,可以使用以下公式代替??????????在你的逻辑中,应该做的诀窍:

$Start = 1 
         + (($i -1) * ($DefaultNumTasksAssigned + 1) 
        - (floor($i / ($Remainder + 1)) * ($i - $Remainder))
$End = $Start + $NumTasksAssigned -1

该公式解释如下:
   1表示您的显示/逻辑是基于一的而不是基于零的    第二个术语是因为我们通常在每次迭代时添加($ DefaultNumTasksAssigned + 1)    第三项提供了对最后几次迭代的修正    它的第一部分(floor($i / ($Remainder + 1))提供0直到$ i到达第一个线程
没有收到一个额外的任务,其后1 第二部分表达了我们需要纠正的程度
$ End的公式更容易,唯一的技巧是减1,这是因为Start和End值是包含的(例如在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

以下是上述

的Python转录
>>> 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 )
>>>

答案 2 :(得分:0)

我认为你solved the wrong half of your problem

除非满足以下所有条件,否则几乎不可能准确地确定完成所有任务所需的时间:

  • 你的任务是100%CPU限制的:也就是说,他们在运行时使用100%的CPU并且不需要做任何I / O
  • 您的任务都不得以任何方式与任何其他任务同步
  • 您拥有与CPU相同数量的线程
  • 运行这些任务的计算机不会同时执行任何其他有趣的任务

实际上,大多数情况下,您的任务是I / O绑定而不是CPU绑定:也就是说,您正在等待某些外部资源,例如从文件读取,从数据库获取或与之通信一台远程电脑。在这种情况下,你只会通过添加更多线程来使事情变得更糟,因为他们都在争夺相同的稀缺资源。

最后,除非你有一些非常奇怪的硬件,否则你实际上不可能同时运行五个线程。 (通常处理器配置至少为两个的倍数。)如果你的任务非常受CPU限制,那么每个CPU的最佳位置大约为1个线程,如果任务花费一半的时间来处理CPU,那么每个CPU大约需要2个线程。他们有一半时间做IO等等。

tl; dr :在我们就此问题向您提出建议之前,我们需要了解您的任务和硬件的更多信息。