Необходимо написать функцию для параллельного выполнения заданий в n параллельных горутинах:
- количество создаваемых горутин не должно зависеть от числа заданий, т.е. функция должна запусать n горутин для параллельно обработки заданий и, возможно, еще несколько вспомогательных горутин;
- функция должна останавливать свою работу, если произошло m ошибок;
- после завершения работы функции (успешного или из-за превышения m) не должно оставаться работающих горутин;
- если задачи работают без ошибок, то выполнятся
len(tasks)
задач (т.е. все задачи); - если в первых m задачах происходят ошибки, то всего выполнится не более n+m задач.
Нужно учесть, что задания могут выполняться разное время, а длина списка задач
len(tasks)
может быть больше или меньше n.
Значение m <= 0 трактуется на усмотрение программиста:
- или это знак игнорировать ошибки в принципе;
- или считать это как "максимум 0 ошибок", значит функция всегда будет возвращать
ErrErrorsLimitExceeded
; - на эту логику следует написать юнит-тест.
(*) Дополнительное задание: написать тест на concurrency без time.Sleep
Придумайте тест, который проверит concurrency другим способом.
Текущий тест "tasks without errors" использует time.Sleep и подсчет времени выполнения, чтобы сделать вывод о конкурентности использования. Проблема тестов на слипчиках в том, что на CI часто не хватает CPU и подобные тесты работают нестабильно.
Подсказка: используйте require.Eventually
.
Имеем 10 задач, n=4 воркера, m=2 ошибки.
- Запускаем:
--------------ok (узнал, что лимит превышен и остановился)
-----------err
-------err
--------------------ok
Выполнится 4 задачи (2 успешно) <= 4 + 2, остальные задачи не берем.
- Другая ситуация, работающие воркеры успели еще взять задач:
------ok--------ok (узнал, что лимит превышен и остановился)
-----------err
---err
--------ok-------ok
Выполнится 6 задач (4 успешно) <= 4 + 2, остальные задачи не берем.
- Ошибок не было:
-------ok-----ok-----ok-----ok (1 воркер выполнил 4 задачи)
-----------ok-------------ok (2 воркер выполнил 2 задачи)
-----ok---------ok---------ok (3 воркер выполнил 3 задачи)
--------------------ok (4 воркер выполнил 1 задачу)
Выполнится 10 задач (10 успешно): задач не осталось, воркеры остановились.
При необходимости можно выделять дополнительные функции / ошибки.
- Пайплайн зелёный - 4 балла
- Добавлены новые юнит-тесты - до 4 баллов
- Понятность и чистота кода - до 2 баллов
- https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem
sync.WaitGroup
go test -v -race -count=100 .
racedetector
ругается на строчку с ассертом в тестах:
- простой случай: после выхода из
Run
остаются висячие горутины, отсюда и получаемdata race
- ассерт в тестах неатомарно обращается кrunTasksCount
, в то время как зомби-горутины атомарно пытаюся её поменять. - случай посложнее: один тест завершается успешно, но висячие горутины, им порожденные, аффектят ассерты в последующих тестах.
- Запускаются лишние горутины (инструкции
go
). Их количество за все время работыRun
должно быть n (плюс, возможно, еще одна-две, если по другому не получается). В некоторых решениях ошибочно контроллируется количество одновременно работающих, а не общее количество.
Решение: внимательно посмотреть места выхода из функции и гарантировать, что все порождённые вами горутины завершились к этому моменту.