Math 编程逻辑-在线程之间拆分任务
假设需要5个线程同时处理数据。同时假设您有89个任务要处理 一拍下来你就知道89/5=17,剩下的是4。分割任务的最佳方法是让4个(剩余的)线程分别处理18个(17+1)任务,然后让1个(#线程-剩余的)线程处理17个任务 这将消除剩余部分。只是为了验证: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-
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 )
>>>