Multithreading 线程池中的工作负载分配算法

Multithreading 线程池中的工作负载分配算法,multithreading,algorithm,Multithreading,Algorithm,假设我们有T个线程,我们想把一个大小为N的问题分配给这些线程。每个线程都会选择该问题的一部分来执行它。每个线程将使用线程id(从0到T-1的数字)、T和N来计算子问题的范围。假设子问题的范围是[s,E],其中s和E属于[0,N] 例如,假设我们有一个整数数组。数组的大小是10。我们想把数组中的每个元素增加1,我们想用4个线程并行执行 线程id=0的第一个线程将使用范围[0,3] 线程id=1的第二个线程将使用范围[3,6] 线程id=2的第三个线程将使用范围[6,8] 线程id=3的第四个线程

假设我们有T个线程,我们想把一个大小为N的问题分配给这些线程。每个线程都会选择该问题的一部分来执行它。每个线程将使用线程id(从0到T-1的数字)、T和N来计算子问题的范围。假设子问题的范围是[s,E],其中s和E属于[0,N]

例如,假设我们有一个整数数组。数组的大小是10。我们想把数组中的每个元素增加1,我们想用4个线程并行执行

  • 线程id=0的第一个线程将使用范围[0,3]
  • 线程id=1的第二个线程将使用范围[3,6]
  • 线程id=2的第三个线程将使用范围[6,8]
  • 线程id=3的第四个线程将使用范围[8,10]

有人知道计算这些范围的快速算法吗?最好没有原子或分支。

如果我理解正确,你在寻找这样一个方程

S = floor(thread_id * N/T)
E = floor((thread_id + 1) * N/T)

如果你先乘(
threadId*N
),然后再除(
/N
),你可以使用整数进行计算,
floor
函数是不必要的。

如果我理解正确,你在寻找这样一个等式

S = floor(thread_id * N/T)
E = floor((thread_id + 1) * N/T)

如果您先乘(
threadId*N
),然后除(
/N
),您可以使用整数进行计算,
floor
函数是不必要的。

我认为这两个示例应该可以工作。所有操作都是整数。但标记为不是整数的操作除外

这一个逻辑更简单,但是它不会按照您的要求分配工作。它会将更大的工作分配给所有员工,但最后一个员工的工作份额会显著降低。理论上这不应该是一个问题,因为一个员工的最大工作量保持不变

items_per_thread = ceil(N/T); // This is not an integer division.
start = thread_id*items_per_thread;
stop = min(start+items_per_thread, N);
这一个应该根据您的需要分配工作

items_per_thread = N/T;
start = thread_id*items_per_thread+min(thread_num, N mod T);
stop = start+items_per_thread;
if(thread_num < N mod T) stop += 1;

我认为这两个例子应该有效。所有的运算都是整数。除了一个标记为不是整数的

这一个逻辑更简单,但是它不会按照您的要求分配工作。它会将更大的工作分配给所有员工,但最后一个员工的工作份额会显著降低。理论上这不应该是一个问题,因为一个员工的最大工作量保持不变

items_per_thread = ceil(N/T); // This is not an integer division.
start = thread_id*items_per_thread;
stop = min(start+items_per_thread, N);
这一个应该根据您的需要分配工作

items_per_thread = N/T;
start = thread_id*items_per_thread+min(thread_num, N mod T);
stop = start+items_per_thread;
if(thread_num < N mod T) stop += 1;

在这个例子中它已经中断了。你会得到(0,2),(2,5)…也许这已经足够了。@luk32它会产生[0,2),[2,4),[4,7),[7,10]。它与op建议的序列有什么不同?1.
(1+1)*10/4对我来说是5,所以它是(2,5)。2.你真的问,(0,2)与(0,3)有什么不同?我不是说这很重要,我是说它是不同的。我是说,也许这个分布就足够了。@luk32 op刚刚要求对范围进行公平划分。当然[0,2]不同于[0,3),但这种差异并不重要。你为什么写我的解决方案“中断”?我认为它完全有效。它中断是因为OP提供了预期的输出,而你的方法提供了不同的结果。“线程id==0的第一个线程将使用范围[0,3)”.最后一次,我说它可能不重要=),也可能不重要。我只是说,它与给定的期望不同。没有更多。它已经在示例中被破坏了。你会得到(0,2),(2,5)…也许它足够了。@luk32它会产生[0,2],[2,4],[4,7),[7,10).它与op提议的序列有什么不同?1.
(1+1)*10/4对我来说是5,所以它是(2,5)。2.你真的问,(0,2)与(0,3)有什么不同?我不是说这很重要,我是说它是不同的。我是说,也许这个分布就足够了。@luk32 op刚刚要求对范围进行公平划分。当然[0,2]不同于[0,3),但这种差异并不重要。你为什么写我的解决方案“中断”?我认为它完全有效。它中断是因为OP提供了预期的输出,而你的方法提供了不同的结果。“线程id==0的第一个线程将使用范围[0,3)”.最后一次,我是说它可能不重要=),也可能不重要。我只是说,它不同于给定的预期。仅此而已。实际上,创建线程的速度比任何合理的方法都慢一千倍。别担心。@MooingDuck你能详细说明一下吗?我误读了吗问题是我是否遗漏了什么?op不要求调度,只要求划分范围。你对这些精确范围有多挑剔?如果一个不同的线程的范围稍微小一点,而不是总是最后一个,可以吗?@ciamej:我的观点是,如果我使用一个速度非常慢的算法来计算范围,它会对整个代码的性能没有可测量的差异,使得整个问题毫无意义。有点像“嘿,我把我所有的东西从A栋搬到B栋;我应该把闹钟留下来减轻体重吗?”@克里斯托波尔斯·查里特:以你的例子来说,如果你得到一个不同的范围,但仍然是一个公平的范围,比如[0,2],[2,5],[5,7],[7,10)?事实上,创建线程的速度比任何合理的计算范围的方法都慢一千倍。别担心。@MooingDuck你能详细说明一下吗?我是误读了问题还是遗漏了什么?op不要求安排时间,只要求对范围进行划分。还有,你对那些精确的范围有多挑剔范围?如果另一个线程的范围比最后一个线程的范围小一些,可以吗?@ciamej:我的观点是,如果我使用一个速度慢得离谱的算法来计算范围,它将不会对整个代码的性能产生可测量的影响,从而使整个问题变得毫无意义“嘿,我要把我所有的东西从A栋搬到B栋;嘘