我得到了一组元素,比如说,从10到21(总是顺序的),我生成相同大小的数组,其中大小由运行时决定。
生成的3个数组的示例(数组#是动态的,所有数组中的元素#也是动态的,其中一些元素可以是0s-不使用):
A1=[10,11,12,13]
A2=[14,15,16,17]
A3=[18,19,20,21]
这些生成的数组将被赋予不同的进程,以便对元素进行一些计算。我的目标是平衡每个将获得数组的进程的负载。我的意思是:
举个例子,有
A1=46
A2=62
A3=78
对每个线程给定的元素的潜在迭代。
我想重新排列初始数组,为每个进程提供相等的工作量,例如:
A1=[21,11,12,13]=57
A2=[14,15,16,17]=62
A3=[18,19,20,10]=67
(不是一个平等的分配,但比最初的更公平)。分布可以是不同的,只要它们接近某个最优分布,并且比第一个和最后一个数组的最坏(初始)情况更好在我看来,使用不同的索引可以实现不同的分布[其中阵列的分割{可能是不均匀的}]
这对给定的例子来说很好,但可能会有一些奇怪的情况。。
因此,我认为这是一个反射问题(由于缺乏正确定义的知识),其中数组应该以对角线穿过它们,如:
10 | 111213
1415 | 1617
181920|21
然后可以进行明显的替换。。
我试着实现类似:
if(rest == 0)
payload_size = (upper-lower)/(processes-1);
else
payload_size = (upper-lower)/(processes-1) + 1;
//printf("payload size: %dn", payload_size);
long payload[payload_size];
int m = 0;
int k = payload_size/2;
int added = 0; //track what been added so far (to skip over already added elements)
int added2 = 0; // same as 'added'
int p = 0;
for (i = lower; i <= upper; i=i+payload_size){
for(j = i; j<(i+payload_size); j++){
if(j <= upper){
if((j-i) > k){
if(added2 > j){
added = j;
payload[(j-i)] = j;
printf("1 adding data: %d at location: %dn", payload[(j-i)], (j-i));
}else{
printf("else..n");
}
}else{
if(added < upper - (m+1)){
payload[(j-i)] = upper - (p*payload_size) - (m++);
added2 = payload[(j-i)];
printf("2 adding data: %d at location: %dn", payload[(j-i)], (j-i));
}else{
payload[(j-i)] = j;
printf("2.5 adding data: %d at location: %dn", payload[(j-i)], (j-i));
}
}
}else{ payload[(j-i)] = ' '; }
}
p++;
k=k/2;
//printf("send to proc: %dn", ((i)/payload_size)%(processes-1)+1);
}
但失败得很惨。
你肯定可以在实现中看到这个问题,因为它的可扩展性差、不完整、混乱、写得不好等等,等等。。。
因此,根据描述,我需要帮助实现或想出一个更好的方法来实现我想要实现的目标。
附言:我需要解决方案尽可能地"在liney中"(避免循环嵌套)——这就是我使用一堆标志和全局索引的原因。
当然,这可以通过额外的循环和不必要的迭代来完成。我邀请那些可以和欣赏t̲h \818 e \818 a \818 r \818 t \818 o \818 f \818 I \818 n \818 d \818 e \818 x \818 I \818 n \818 g \818的人。
我确信有一个解决方案,但我无法进行适当的谷歌查询来找到它
提示?我想用索引%size_of_my_data来完成这项任务。。
p.S.应用程序:此处介绍
这是我使用deque编写的一个O(n)解决方案(双端队列,不需要deque,可以使用简单的数组,但由于popRight和popLeft,deque使代码变得干净)。代码是Python,而不是伪代码,但它应该很容易理解(因为它是Python)
def balancingSumProblem(seqStart = None, seqStop = None, numberOfArrays = None):
from random import randint
from collections import deque
seq = deque(xrange(seqStart or randint(1, 10),
seqStop and seqStop + 1 or randint(11,30)))
arrays = [[] for _ in xrange(numberOfArrays or randint(1,6))]
print "# of elements: {}".format(len(seq))
print "# of arrays: {}".format(len(arrays))
averageNumElements = float(len(seq)) / len(arrays)
print "average number of elements per array: {}".format(averageNumElements)
oddIteration = True
try:
while seq:
for array in arrays:
if len(array) < averageNumElements and oddIteration:
array.append(seq.pop()) # pop() is like popright()
elif len(array) < averageNumElements:
array.append(seq.popleft())
oddIteration = not oddIteration
except IndexError:
pass
print arrays
print [sum(array) for array in arrays]
balancingSumProblem(10,21,3) # Given Example
print "n---------n"
balancingSumProblem() # Randomized Test
基本上,从一次迭代到另一次迭代,它在抓取大元素并在数组中均匀分布和抓取小元素并在阵列中均匀分布之间交替。它从out到in(尽管您可以从in到out),并尝试使用每个数组的平均元素数来进一步平衡它。
它并不是所有测试都100%准确,但它在大多数随机测试中都做得很好。您可以尝试在此处运行代码:http://repl.it/cJg
通过一个简单的序列分配,您可以依次迭代地将最小和最大元素添加到每个列表中。有一些终止细节需要解决,但这只是一般的想法。应用于您的示例,输出看起来像:
john-schultzs-macbook-pro:~ jschultz$ ./a.out
10 21 13 18 = 62
11 20 14 17 = 62
12 19 15 16 = 62
当num_procs平均划分num_elems时,像这样的简单反射分配将是最佳的。它将是次优的,但仍然不错,当它不是:
#include <stdio.h>
int compute_dist(int lower, int upper, int num_procs)
{
if (lower > upper || num_procs <= 0)
return -1;
int num_elems = upper - lower + 1;
int num_elems_per_proc_floor = num_elems / num_procs;
int num_elems_per_proc_ceil = num_elems_per_proc_floor + (num_elems % num_procs != 0);
int procs[num_procs][num_elems_per_proc_ceil];
int i, j, sum;
// assign pairs of (lower, upper) to each process until we can't anymore
for (i = 0; i + 2 <= num_elems_per_proc_floor; i += 2)
for (j = 0; j < num_procs; ++j)
{
procs[j][i] = lower++;
procs[j][i+1] = upper--;
}
// handle left overs similarly to the above
// NOTE: actually you could use just this loop alone if you set i = 0 here, but the above loop is more understandable
for (; i < num_elems_per_proc_ceil; ++i)
for (j = 0; j < num_procs; ++j)
if (lower <= upper)
procs[j][i] = ((0 == i % 2) ? lower++ : upper--);
else
procs[j][i] = 0;
// print assignment results
for (j = 0; j < num_procs; ++j)
{
for (i = 0, sum = 0; i < num_elems_per_proc_ceil; ++i)
{
printf("%d ", procs[j][i]);
sum += procs[j][i];
}
printf(" = %dn", sum);
}
return 0;
}
int main()
{
compute_dist(10, 21, 3);
return 0;
}
我使用了这个实现,我在本报告中提到了它(实现适用于我用于测试(1-15K)(1-30K)和(1-100K)数据集的案例。我并不是说它对所有情况都有效):
int aFunction(long lower, long upper, int payload_size, int processes)
{
long result, i, j;
MPI_Status status;
long payload[payload_size];
int m = 0;
int k = (payload_size/2)+(payload_size%2)+1;
int lastAdded1 = 0;
int lastAdded2 = 0;
int p = 0;
int substituted = 0;
int allowUpdate = 1;
int s;
int times = 1;
int times2 = 0;
for (i = lower; i <= upper; i=i+payload_size){
for(j = i; j<(i+payload_size); j++){
if(j <= upper){
if(k != 0){
if((j-i) >= k){
payload[(j-i)] = j- (m);
lastAdded2 = payload[(j-i)];
}else{
payload[(j-i)] = upper - (p*payload_size) - (m++) + (p*payload_size);
if(allowUpdate){
lastAdded1 = payload[(j-i)];
allowUpdate = 0;
}
}
}else{
int n;
int from = lastAdded1 > lastAdded2 ? lastAdded2 : lastAdded1;
from = from + 1;
int to = lastAdded1 > lastAdded2 ? lastAdded1 : lastAdded2;
int tempFrom = (to-from)/payload_size + ((to-from)%payload_size>0 ? 1 : 0);
for(s = 0; s < tempFrom; s++){
int restIndex = -1;
for(n = from; n < from+payload_size; n++){
restIndex = restIndex + 1;
payload[restIndex] = ' ';
if(n < to && n >= from){
payload[restIndex] = n;
}else{
payload[restIndex] = ' ';
}
}
from = from + payload_size;
}
return 0;
}
}else{ payload[(j-i)] = ' '; }
}
p++;
k=(k/2)+(k%2)+1;
allowUpdate = 1;
}
return 0;
}