Максимизация использования рабочих потоков - PullRequest
1 голос
/ 05 августа 2010

Чтобы решить проблему (и лучше понять многозадачность), я написал небольшую реализацию пула потоков. Этот пул потоков раскручивает несколько рабочих потоков, которые выталкивают задачи из очереди по мере их добавления клиентом пула потоков. Для целей этого вопроса, когда очередь задач пуста, все рабочие потоки завершаются.

После некоторого базового тестирования я обнаружил, что приложение тратит ~ 60% своего времени на ожидание блокировки очереди. Предположительно это в основном происходит в рабочих потоках.

Это просто признак того, что я не даю рабочим потокам достаточно информации, или что-то еще? Есть ли что-то простое, что я могу упустить, чтобы увеличить пропускную способность рабочего потока?

РЕДАКТИРОВАТЬ : Вот несколько грубых псевдокодов, которые должны что-то проиллюстрировать. Это единственные два места, где блокировка получается / снимается во время выполнения рабочих потоков (что составляет подавляющее большинство времени работы приложения).

std::list<task_t> task_list;

// Called by the client to add tasks to the thread pool
void insert_task(const task_t& task)
{
    lock_type listlock(task_mutex);

    task_list.push_back(task);
}

// The base routine of each thread in the pool. Some details
// such as lifetime management have been omitted for clarity.
void worker_thread_base()
{
    while (true)
    {
        task_t task;

        {
        lock_type listlock(task_mutex);

        if (task_list.empty())
            continue;

        task = task_list.front();

        task_list.pop_front();
        }

        do_task(task);
    }
}

Ответы [ 2 ]

0 голосов
/ 05 августа 2010

Ваш дизайн построен там, где каждая нить сидит и «крутится», пытаясь получить блокировку. Это будет происходить постоянно, если только каждый рабочий поток не выполняет работу - в этом случае блокировка останется неприобретенной, и работа будет выполнена.

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

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

Намного лучше было бы использовать какую-либо форму очереди без блокировки для вашей рабочей очереди, так как это могло бы предотвратить ожидание в этот момент. Кроме того, наличие дескриптора ожидания, который может блокировать рабочие потоки до тех пор, пока в очереди не будет работать, предотвратит ненужное вращение.

0 голосов
/ 05 августа 2010

Вы пытаетесь сделать это с помощью одной блокировки, нескольких блокировок? Mutexs? Какую семантику ожидания вы используете?

Я бы догадался из вашего описания (и это всего лишь предположение), что у вас есть что-то похожее на:

lock(theLock) {
 // ... do lots of work ...
}

В вашем основном потоке, который содержит код для отправки в легкие потоки. Одна из причин, по которой вы можете увидеть сокращенное время ожидания, заключается в том, что вам необходимо получить сигналы от запущенных потоков о том, что они были поставлены в очередь и ожидают выполнения (опять же, это предположение, поскольку вы не давали никакого кода).

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

Хотя, не видя вашей текущей реализации, я не уверен, что смогу сделать намного больше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...