C中的工作分配算法(do while issue)
Work distribution algorithm in C (do while issue)
所以我正在尝试开发一种算法来在线程之间平均分配工作,但它有点独特。正在完成的工作是文件比较,我们有一个文件列表(比方说 10 个文件)。我们不想将文件 1 与文件 1 进行比较,因此每个文件都会跳过自身比较。文件 1 会将自己与文件 2 到 10 进行比较,文件 2 会将自己与文件 3 到文件 10 进行比较,依此类推。因此,当我们在文件比较列表中向下移动时,文件比较的数量会下降。这是我遇到问题的小片段(特别是 do-while 循环)
// Get first pass file chunks
printf("Split approximation: ");
for (int i = 0; i < num_threads; i++)
{
file_chunks[i] = (int)floor((double)num_file_compares / (double)num_threads);
printf("%d ", file_chunks[i]);
}
printf("\n");
// Adjust file chunks to contain all files
for (int i = 0; i < num_threads; i++)
{
file_chunk_sum = file_chunk_sum + file_chunks[i];
}
append_count = num_file_compares - file_chunk_sum;
printf("Need to append last %d\n", append_count);
append_index = num_threads;
do
{
printf("im in the do while...\n");
printf("append count is: %d\n", append_count);
printf("why am i here?\n");
append_index = append_index - 1;
file_chunks[append_index] = file_chunks[append_index] + 1;
append_count = append_count - 1;
} while (append_count > 0);
printf("Final split: ");
for (int i = 0; i < num_threads; i++)
{
printf("%d ", file_chunks[i]);
}
printf("\n");
对于 20 个文件(190 次文件比较)和 5 个线程的输入,拆分近似将是每个线程 38 个文件比较的均匀拆分。 append 计数为 0,但它仍然跳入 do-while 循环。知道为什么吗?
那些printf
的输出是
Number of files: 20
Number of threads: 5
Number of file compares: 190
Split approximation: 38 38 38 38 38
Need to append last 0
im in the do while...
append count is: 0
why am i here?
Final split: 38 38 38 38 39
A 'do while' 总是至少执行一次。如果您不希望它以这种方式运行,请尝试使用常规 'while'.
"do while" C 中的循环总是至少执行一次,你想要的是 "while" 循环
而不是使用 do
...while
,您只想使用 while
。这会在循环顶部而不是底部执行检查。
while (append_count > 0)
{
printf("im in the while...\n");
printf("append count is: %d\n", append_count);
printf("why am i here?\n");
append_index = append_index - 1;
file_chunks[append_index] = file_chunks[append_index] + 1;
append_count = append_count - 1;
}
我从一条评论中了解到您已经习惯了 Fortran。以下是如何用更像 C 的 C 编写代码:
// Get first pass file chunks
printf("Split approximation: "); // fputs("...", stdout); is a good choice for non-formatted output, but it's clunkier to write.
// puts() confusingly tacks on a newline while fputs() doesn't, so puts(s) *isn't* just fputs(s, stdout).
// Every time you use printf, remember that the first argument is being parsed as a format string, so you have to make sure you don't use a % in it, unless you write printf("%s", "...")
for (int i = 0; i < num_threads; i++)
{
// opening brace on a line by itself is a waste of space, IMO, except for the first line of a function.
// but it's better to be consistent than to use your personal favourite style.
file_chunks[i] = num_file_compares / num_threads; // what's wrong with integer division here? I think this rounds the same as your old // (int)floor((double)num_file_compares / (double)num_threads);
printf("%d ", file_chunks[i]);
}
putchar('\n'); // here we can use a lighter-weight i/o function
int file_chunk_sum = 0; // don't forget to initialize your variables. And in C99 (or C++), many people prefer to declare them near where they're used instead of in a big block at the top of a function.
// Adjust file chunks to contain all files
for (int i = 0; i < num_threads; i++) // don't use a loop to do this: see below
{
file_chunk_sum += file_chunks[i]; // += saves human readers of your code from having to notice that it's the same variable on both sides of the =
}
append_count = num_file_compares - file_chunk_sum;
/* or you could have started with int append_count = num_f_c; and subtracted f_c[i] in the loop
* or instead of summing, you could just take advantage of the fact that every f_c[i] has the same known value.
* integer multiply FTW.
* or even just make use of the remainder from your integer division and save the multiply. (x86 at least computes remainders at the same time as dividend, so % is free if you're already doing /.)
*/
// append_count = num_file_compares - (file_chunks[0] * num_threads);
// append_count = num_file_compares % num_threads; // or remainder
printf("Need to append last %d\n", append_count);
// append_index = num_threads; // make this a loop variable if you like. Some people would consider packing too much stuff into a for loop to be less readable
// actually, we can simplify the loop a *lot* by getting rid of unneeded variables. Adjust if desired to still put the remainder counts on the later indices, rather than earlier.
for (int i=append_count ; i > 0 ; i--)
{
// count downwards to print a descending count, same as your old code
printf("I'm in the append loop...\n" // nobody like "im" instead of I'm.
"append count is: %d\n"
"why am i here?\n", append_count);
/* string literals concatenate automatically.
* Writing multi-line string constants this way is generally preferred
* to having literal newlines inside double-quotes. That can lead to problems with line endings (Unix lf vs. DOS cr/lf vs. Mac cr).
*/
file_chunks[i]++; // Much easier to read ++ when using long variable names.
}
printf("Final split: ");
for (int i = 0; i < num_threads; i++)
{
printf("%d ", file_chunks[i]);
}
putchar('\n');
所以我正在尝试开发一种算法来在线程之间平均分配工作,但它有点独特。正在完成的工作是文件比较,我们有一个文件列表(比方说 10 个文件)。我们不想将文件 1 与文件 1 进行比较,因此每个文件都会跳过自身比较。文件 1 会将自己与文件 2 到 10 进行比较,文件 2 会将自己与文件 3 到文件 10 进行比较,依此类推。因此,当我们在文件比较列表中向下移动时,文件比较的数量会下降。这是我遇到问题的小片段(特别是 do-while 循环)
// Get first pass file chunks
printf("Split approximation: ");
for (int i = 0; i < num_threads; i++)
{
file_chunks[i] = (int)floor((double)num_file_compares / (double)num_threads);
printf("%d ", file_chunks[i]);
}
printf("\n");
// Adjust file chunks to contain all files
for (int i = 0; i < num_threads; i++)
{
file_chunk_sum = file_chunk_sum + file_chunks[i];
}
append_count = num_file_compares - file_chunk_sum;
printf("Need to append last %d\n", append_count);
append_index = num_threads;
do
{
printf("im in the do while...\n");
printf("append count is: %d\n", append_count);
printf("why am i here?\n");
append_index = append_index - 1;
file_chunks[append_index] = file_chunks[append_index] + 1;
append_count = append_count - 1;
} while (append_count > 0);
printf("Final split: ");
for (int i = 0; i < num_threads; i++)
{
printf("%d ", file_chunks[i]);
}
printf("\n");
对于 20 个文件(190 次文件比较)和 5 个线程的输入,拆分近似将是每个线程 38 个文件比较的均匀拆分。 append 计数为 0,但它仍然跳入 do-while 循环。知道为什么吗?
那些printf
的输出是
Number of files: 20
Number of threads: 5
Number of file compares: 190
Split approximation: 38 38 38 38 38
Need to append last 0
im in the do while...
append count is: 0
why am i here?
Final split: 38 38 38 38 39
A 'do while' 总是至少执行一次。如果您不希望它以这种方式运行,请尝试使用常规 'while'.
"do while" C 中的循环总是至少执行一次,你想要的是 "while" 循环
而不是使用 do
...while
,您只想使用 while
。这会在循环顶部而不是底部执行检查。
while (append_count > 0)
{
printf("im in the while...\n");
printf("append count is: %d\n", append_count);
printf("why am i here?\n");
append_index = append_index - 1;
file_chunks[append_index] = file_chunks[append_index] + 1;
append_count = append_count - 1;
}
我从一条评论中了解到您已经习惯了 Fortran。以下是如何用更像 C 的 C 编写代码:
// Get first pass file chunks
printf("Split approximation: "); // fputs("...", stdout); is a good choice for non-formatted output, but it's clunkier to write.
// puts() confusingly tacks on a newline while fputs() doesn't, so puts(s) *isn't* just fputs(s, stdout).
// Every time you use printf, remember that the first argument is being parsed as a format string, so you have to make sure you don't use a % in it, unless you write printf("%s", "...")
for (int i = 0; i < num_threads; i++)
{
// opening brace on a line by itself is a waste of space, IMO, except for the first line of a function.
// but it's better to be consistent than to use your personal favourite style.
file_chunks[i] = num_file_compares / num_threads; // what's wrong with integer division here? I think this rounds the same as your old // (int)floor((double)num_file_compares / (double)num_threads);
printf("%d ", file_chunks[i]);
}
putchar('\n'); // here we can use a lighter-weight i/o function
int file_chunk_sum = 0; // don't forget to initialize your variables. And in C99 (or C++), many people prefer to declare them near where they're used instead of in a big block at the top of a function.
// Adjust file chunks to contain all files
for (int i = 0; i < num_threads; i++) // don't use a loop to do this: see below
{
file_chunk_sum += file_chunks[i]; // += saves human readers of your code from having to notice that it's the same variable on both sides of the =
}
append_count = num_file_compares - file_chunk_sum;
/* or you could have started with int append_count = num_f_c; and subtracted f_c[i] in the loop
* or instead of summing, you could just take advantage of the fact that every f_c[i] has the same known value.
* integer multiply FTW.
* or even just make use of the remainder from your integer division and save the multiply. (x86 at least computes remainders at the same time as dividend, so % is free if you're already doing /.)
*/
// append_count = num_file_compares - (file_chunks[0] * num_threads);
// append_count = num_file_compares % num_threads; // or remainder
printf("Need to append last %d\n", append_count);
// append_index = num_threads; // make this a loop variable if you like. Some people would consider packing too much stuff into a for loop to be less readable
// actually, we can simplify the loop a *lot* by getting rid of unneeded variables. Adjust if desired to still put the remainder counts on the later indices, rather than earlier.
for (int i=append_count ; i > 0 ; i--)
{
// count downwards to print a descending count, same as your old code
printf("I'm in the append loop...\n" // nobody like "im" instead of I'm.
"append count is: %d\n"
"why am i here?\n", append_count);
/* string literals concatenate automatically.
* Writing multi-line string constants this way is generally preferred
* to having literal newlines inside double-quotes. That can lead to problems with line endings (Unix lf vs. DOS cr/lf vs. Mac cr).
*/
file_chunks[i]++; // Much easier to read ++ when using long variable names.
}
printf("Final split: ");
for (int i = 0; i < num_threads; i++)
{
printf("%d ", file_chunks[i]);
}
putchar('\n');