0

假设您想要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

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

+0

为什么你想要5个线程同时处理?这似乎是一个非常奇怪的数字,只是拉出空气。 –

回答

1

我第二次将哈尔顿的话。您可以一次只给一个任务提供一个任务(或者一次执行几个任务,具体取决于是否有大量开销,即,相对于启动/回收线程的成本,个别任务通常以非常快的速度完成)。你的后续评论有效地解释了你的“线索”带来了巨大的创造成本,因此你希望尽可能多地为它们提供一次工作,而不是浪费时间创造新的“线程”,每个线程都需要少量的工作。

反正...要去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至$我到达的第一个线程
     不接受一个额外的任务,此后1。
     第二部分表达了我们需要纠正多少。

为$结束的公式是更加容易,唯一的招是减1,这是因为开始值和结束值是包含性的(因此,例如,1之间的19有19个任务不是18)

的以下逻辑的稍微修改一块也应该工作,避免了通过保持$开始变量的运行选项卡,而不是每次都重新计算它的“神奇”的公式..

$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) 
>>> 
+0

你忘了保留'$ NumTasksAssigned' - 因为这样你的输出不正确。 '$ Start = $ Start + $ DefaultNumTasksAssigned'应该是'$ Start = $ Start + $ NumTasksAssigned'。这将使它适合这个例子,但如果我改变'$ NumTasks = 11',它会失败。 – ParoX

+0

@BHare。你是对的,保持$ NumTasksAssigned是有用的。看到我的晚餐后编辑(我的代码更好,肚子饱满)......我以为我可以摆脱,因为_last_“线程”不会获得最大的任务分配量,但这当然只是给人的印象由特定的89值。 88例如。将有两个“线程”,少一个任务。等等。 – mjv

+0

这个例子使得任务89不会生效。输出在这里:http://pastebin.com/raw.php?i=avT3MD8m - 无论如何,没有争议的一点,因为我取得了成功,使用您的原始作为基地。一个工作模式在这里:http://pastebin.com/raw.php?i=He86vE97 - 元数学答案使它更简单:http://math.stackexchange.com/questions/46014/programming-logic-splitting-线程之间的任务...如果你希望被接受,请相应地更新你的答案。否则,病态的MOD将它关闭。 – ParoX

7

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

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

把它想象成一个银行,每个柜员一条线,一条线和很多出纳员。在前者中,你可能会被卡在存钱币的人的后面,并逐个计算出来,后者可以到达下一个可用的出纳员,而PocketChange先生却数不胜数。

+0

我使用的语言实际上不支持真正的多线程,而是支持并行处理。这里的想法是尽可能长时间地保持这个过程,因为“释放”意味着一个过程关闭,另一个过程是开放的,这比处理本身需要更多的时间。我的方法是在大多数时间运行5个并发进程,每个进程同时处理他们自己的小任务。 – ParoX

+0

@BHare:那么你为什么要标记'c#'和'php'这个问题? –

+0

这很好,但如果您拥有对资源的共享访问权限,则使用共享队列作为任务源与预分配列表之间没有区别。当然,队列会添加某种类型的同步(但这可能不是问题,具体取决于您的多任务处理)。 –

0

我想你已经solved the wrong half of your problem

这将是几乎不可能精确地确定它会完成所有任务的时间,除非以下所有条件都为真:

  • 你的任务是100%的CPU绑定的:那就是,他们使用100%的CPU运行时,并不需要做任何I/O
  • 没有你的任务以任何方式与任何您的其他任务同步
  • 你有一样多的线程,你有CPU的
  • 运行这些任务的计算机未执行同时

在实践纽约其他有趣的任务,大多数的时候,你的任务是I/O密集型而非CPU密集型的:那就是,你在等待一些外部资源,如从阅读一个文件,从数据库中取出或与远程计算机通信。在这种情况下,你只会通过增加更多的线程来让事情变得更糟,因为它们都在争夺相同的稀缺资源。最后,除非你有一些非常奇怪的硬件,否则你不可能真正有5个线程同时运行。 (通常处理器配置至少有两个倍数)。如果你的任务是CPU限制的,通常情况下,每个CPU的最佳位置约为1个线程,如果任务花费了一半的CPU时间,一半的时间在做IO等

tl; dr:我们需要知道更多关于您的任务和硬件的样子,然后才能就此问题为您提供建议。

+0

它们不是真正的线程,而是过程。每个进程将处理一个winhttp GET或POST请求(不支持语言中的异步请求)。我选择了5个,因为它似乎是测试中最快的。 – ParoX

+0

@BHare:这不会使我写的任何内容无效。如果之前的测试发现5个线程是最快的,那意味着CPU活动和I/O活动之间可能会有大约80%-20%的分离,并且它可能是(1)占用80%时间的CPU工作,你是在一台四核机器上,或者(2)它占用了80%-100%的I/O时间,但是你可以一次有效地交叉处理四个请求。我有一个预感,(2)是你的瓶颈,因为你提到你在做HTTP,而浏览器通常只向一个服务器发出4个请求。 –