85 lines
5.8 KiB
Markdown
85 lines
5.8 KiB
Markdown
|
## Домашнее задание №5 «Параллельное исполнение»
|
|||
|
Необходимо написать функцию для параллельного выполнения заданий в n параллельных горутинах:
|
|||
|
* количество создаваемых горутин не должно зависеть от числа заданий, т.е. функция должна запускать n горутин для конкурентной обработки заданий и, возможно, еще несколько вспомогательных горутин;
|
|||
|
* функция должна останавливать свою работу, если произошло m ошибок;
|
|||
|
* после завершения работы функции (успешного или из-за превышения m) не должно оставаться работающих горутин.
|
|||
|
|
|||
|
Нужно учесть, что задания могут выполняться разное время, а длина списка задач
|
|||
|
`len(tasks)` может быть больше или меньше n.
|
|||
|
|
|||
|
Значение m <= 0 трактуется на усмотрение программиста:
|
|||
|
- или это знак игнорировать ошибки в принципе;
|
|||
|
- или считать это как "максимум 0 ошибок", значит функция всегда будет возвращать
|
|||
|
`ErrErrorsLimitExceeded`;
|
|||
|
- на эту логику следует написать юнит-тест.
|
|||
|
|
|||
|
Граничные случаи:
|
|||
|
* если задачи работают без ошибок, то выполнятся `len(tasks)` задач, т.е. все задачи;
|
|||
|
* если в первых выполненных m задачах (или вообще всех) происходят ошибки, то всего выполнится не более n+m задач.
|
|||
|
|
|||
|
|
|||
|
**(*) Дополнительное задание: написать тест на 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 баллов
|
|||
|
|
|||
|
#### Зачёт от 7 баллов
|
|||
|
|
|||
|
### Подсказки
|
|||
|
- https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem
|
|||
|
- `sync.WaitGroup`
|
|||
|
- `go test -v -race -count=100 .`
|
|||
|
|
|||
|
### Частые ошибки
|
|||
|
1) `racedetector` ругается на строчку с ассертом в тестах:
|
|||
|
- простой случай: после выхода из `Run` остаются висячие горутины, отсюда и получаем `data race` -
|
|||
|
ассерт в тестах неатомарно обращается к `runTasksCount`, в то время как зомби-горутины атомарно пытаюся её поменять.
|
|||
|
- случай посложнее: один тест завершается успешно, но висячие горутины, им порожденные, аффектят ассерты в
|
|||
|
последующих тестах.
|
|||
|
2) Запускаются лишние горутины (инструкции `go`). Их количество за все время работы `Run` должно быть n (плюс, возможно, еще одна-две, если по другому не получается). В некоторых решениях ошибочно контроллируется количество одновременно работающих, а не общее количество.
|
|||
|
|
|||
|
**Решение**: внимательно посмотреть места выхода из функции и гарантировать, что все порождённые вами горутины
|
|||
|
завершились к этому моменту.
|