Как рассчитать равномерно распределенное количество заданий для фиксированного количества потоков?

#c

#c

Вопрос:

Давайте предположим, что у меня есть tasks количество задач и threads количество потоков для их выполнения. Каждый поток может выполняться только один раз, поэтому я хочу равномерно распределить эти задачи по существующим потокам. Чтобы рассчитать количество задач в потоке, я написал это простое приложение:

 #include <iostream>
using namespace std;

int main(){
    int tasks = 15; 
    int threads = 8; 

    if(tasks < threads)
        threads = tasks;

    int tasksPerThread = tasks / threads;

    for (int i = 0, start = 1; i < threads; i  ) {
        start = tasksPerThread * i   1;
        int end = start   tasksPerThread - 1;
        if (i == threads - 1 amp;amp; end < tasks)
            end = tasks;
        if(start == end)
            cout << "Thread " << i   1 << ": task " << end << endl;
        else
            cout << "Thread " << i   1 << ": task " << start << "-" << end << endl;
    }
    return 0;
}
  

При наличии 16 задач и 8 потоков каждый поток получит по 2 задачи. Но в этом случае при наличии 15 задач с 8 потоками я получаю в результате следующее распределение:

  • Поток 1: задача 1
  • Поток 2: задача 2
  • Поток 3: задача 3
  • Поток 4: задача 4
  • Поток 5: задача 5
  • Поток 6: задача 6
  • Поток 7: задача 7
  • Поток 8: задача 8-15

Последний поток выполнял бы многие задачи по сравнению с другими, и именно поэтому я хотел бы исправить это распределение, чтобы оно было примерно таким:

  • Поток 1: задача 1-2
  • Поток 2: задача 3-4
  • Поток 3: задача 5-6
  • Поток 4: задача 7-8
  • Поток 5: задача 9-10
  • Поток 6: задача 11-12
  • Поток 7: задача 13-14
  • Поток 8: задача 15

Мне нужна помощь в исправлении приведенного выше кода, чтобы получить такой результат, при котором каждый поток выполняет одинаковое количество задач. Спасибо.

РЕДАКТИРОВАТЬ: Вот решение благодаря формуле @shananton.

 int tasks = 15;
int threads = 8;

if (tasks < threads)
    threads = tasks;

int start, usedTasks = 0, tasks_for_this_thread = 0;

for (int i = 0; i < threads; i  ) {
    usedTasks  = tasks_for_this_thread;
    start = usedTasks   1;
    tasks_for_this_thread = tasks / threads   (i < tasks % threads);
    int end = start   tasks_for_this_thread - 1;

    if (start == end)
        cout << "Thread " << i   1 << ": task " << end << endl;
    else
        cout << "Thread " << i   1 << ": task " << start << "-" << end << endl;
}
  

Комментарии:

1. Разве циклический перебор недостаточно хорош? Во-первых, назначьте каждому потоку задачу. Если остались задачи, назначьте оставшиеся задачи каждому потоку. Простой алгоритм хорош и его легче поддерживать.

Ответ №1:

Чтобы заранее рассчитать количество задач на поток, вы можете использовать эту формулу:

 int tasks = 10;
int threads = 3;

for (int i = 0; i < threads;   i) {
    int tasks_for_this_thread = tasks / threads   (i < tasks % threads);
    // do whatever you want to 
}
  

Например, для 10 задач и 3 потоков задачи распределяются как 4, 3, 3.

Комментарии:

1. ДА. Эта формула была ключевой. Я опубликовал решение в своем первоначальном сообщении. Спасибо!

Ответ №2:

Простой циклический перебор путем перебора задач.

 int tasks(15);
int threads(8);

int thread_index(0);
for( int i = 0 ; i < tasks; i  ){
    set( thread_index , i ); // pseudo code to start the task 
    thread_index = ( thread_index 1 ) % threads;
}