Сообщение Re: Красивое решение для задачи с потоками от 13.03.2015 9:21
Изменено 13.03.2015 11:20 Sinix
Здравствуйте, Cynic, Вы писали:
C>Требуется найти "красивое" решение для следующей задачи.
C>Есть четыре потока: один "управляющий", и три "вычислительных". Задача "управляющего потока" раздавать задачи "вычислительным потокам", а задача "вычислительных" выполнять эти задачи. При этом "вычислительные потоки" должны работать по следующему алгоритму:
Таски наше всё. Пишется за 5 минут, работает с первого раза.
UPD: НЕ работает с первого раза, см ниже.
Это на случай, если получение-обработку надо разделить. Если не надо, всё тоже несложно — producer-consumer и ConcurrentQueue.
UPD: Позорище и ещё раз позорище
Вот это
надо заменить на
С (2) всё понятно — надо обрабатывать результат, а не "Enumerable.Range(0, taskCount)".
С (1) всё чуть сложнее. Кто сообразит, почему там нужен .ToArray() (подчеркнул) — тому пряник.
Мораль: пишите ассерты.
C>Требуется найти "красивое" решение для следующей задачи.
C>Есть четыре потока: один "управляющий", и три "вычислительных". Задача "управляющего потока" раздавать задачи "вычислительным потокам", а задача "вычислительных" выполнять эти задачи. При этом "вычислительные потоки" должны работать по следующему алгоритму:
Таски наше всё. Пишется за 5 минут, работает с первого раза.
UPD: НЕ работает с первого раза, см ниже.
код | |
| |
Это на случай, если получение-обработку надо разделить. Если не надо, всё тоже несложно — producer-consumer и ConcurrentQueue.
UPD: Позорище и ещё раз позорище
Вот это
while (!ct.IsCancellationRequested)
{
state = State.GetResult;
var tasks = Enumerable.Range(0, taskCount).Select(i => GetNextResult(num + i)); // (1)
await Task.WhenAll(tasks);
state = State.Process;
tasks = Enumerable.Range(0, taskCount).Select(i => Process(i, num + i)); // (2)
await Task.WhenAll(tasks);
state = State.Idle;
num += taskCount;
}
надо заменить на
while (!ct.IsCancellationRequested)
{
state = State.GetResult;
var tasks = Enumerable.Range(0, taskCount).Select(i => GetNextResult(num + i)).ToArray(); // (1)
await Task.WhenAll(tasks);
state = State.Process;
var tasks2 = tasks.Select((t, i) => Process(i, t.Result)).ToArray(); // (2)
await Task.WhenAll(tasks2);
num += taskCount;
state = State.Idle;
}
С (2) всё понятно — надо обрабатывать результат, а не "Enumerable.Range(0, taskCount)".
С (1) всё чуть сложнее. Кто сообразит, почему там нужен .ToArray() (подчеркнул) — тому пряник.
Мораль: пишите ассерты.
Re: Красивое решение для задачи с потоками
Здравствуйте, Cynic, Вы писали:
C>Требуется найти "красивое" решение для следующей задачи.
C>Есть четыре потока: один "управляющий", и три "вычислительных". Задача "управляющего потока" раздавать задачи "вычислительным потокам", а задача "вычислительных" выполнять эти задачи. При этом "вычислительные потоки" должны работать по следующему алгоритму:
Таски наше всё. Пишется за 5 минут, работает с первого раза.
UPD: НЕ работает с первого раза, см ниже.
Это на случай, если получение-обработку надо разделить. Если не надо, всё тоже несложно — producer-consumer и ConcurrentQueue.
UPD: Позорище и ещё раз позорище
Вот это
надо заменить на
С (2) всё понятно — надо обрабатывать результат, а не "Enumerable.Range(0, taskCount)".
С (1) всё чуть сложнее. Кто сообразит, почему там нужен .ToArray() (подчеркнул) — тому пряник.
UPD2:
Ну и правильный вариант использования "Task.WhenAll()", чтобы закрыть тему.
Мораль: пишите ассерты.
C>Требуется найти "красивое" решение для следующей задачи.
C>Есть четыре потока: один "управляющий", и три "вычислительных". Задача "управляющего потока" раздавать задачи "вычислительным потокам", а задача "вычислительных" выполнять эти задачи. При этом "вычислительные потоки" должны работать по следующему алгоритму:
Таски наше всё. Пишется за 5 минут, работает с первого раза.
UPD: НЕ работает с первого раза, см ниже.
код | |
| |
Это на случай, если получение-обработку надо разделить. Если не надо, всё тоже несложно — producer-consumer и ConcurrentQueue.
UPD: Позорище и ещё раз позорище
Вот это
while (!ct.IsCancellationRequested)
{
state = State.GetResult;
var tasks = Enumerable.Range(0, taskCount).Select(i => GetNextResult(num + i)); // (1)
await Task.WhenAll(tasks);
state = State.Process;
tasks = Enumerable.Range(0, taskCount).Select(i => Process(i, num + i)); // (2)
await Task.WhenAll(tasks);
state = State.Idle;
num += taskCount;
}
надо заменить на
while (!ct.IsCancellationRequested)
{
state = State.GetResult;
var tasks = Enumerable.Range(0, taskCount).Select(i => GetNextResult(num + i)).ToArray(); // (1)
await Task.WhenAll(tasks);
state = State.Process;
var tasks2 = tasks.Select((t, i) => Process(i, t.Result)).ToArray(); // (2)
await Task.WhenAll(tasks2);
num += taskCount;
state = State.Idle;
}
С (2) всё понятно — надо обрабатывать результат, а не "Enumerable.Range(0, taskCount)".
С (1) всё чуть сложнее. Кто сообразит, почему там нужен .ToArray() (подчеркнул) — тому пряник.
UPD2:
Ну и правильный вариант использования "Task.WhenAll()", чтобы закрыть тему.
while (!ct.IsCancellationRequested)
{
state = State.GetResult;
var resultTasks = Enumerable.Range(0, taskCount).Select(i => GetNextResult(num + i));
var results = await Task.WhenAll(resultTasks);
state = State.Process;
var processingTasks = results.Select((result, ix) => Process(ix, result)).ToArray();
await Task.WhenAll(processingTasks);
num += taskCount;
state = State.Idle;
}
Мораль: пишите ассерты.