unpack_string/hw05_parallel_execution/README.md

85 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## Домашнее задание №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 (плюс, возможно, еще одна-две, если по другому не получается). В некоторых решениях ошибочно контроллируется количество одновременно работающих, а не общее количество.
**Решение**: внимательно посмотреть места выхода из функции и гарантировать, что все порождённые вами горутины
завершились к этому моменту.