Нужен пул из n работников и общая отмена при ошибке номер m+1. Уже запущенные задачи должны поддерживать context, иначе гарантировать их остановку нельзя.
Одновременный запуск задач с ограничением количества ошибок
Нужен пул из n работников и общая отмена при ошибке номер m+1. Уже запущенные задачи должны поддерживать context, иначе гарантировать их остановку нельзя.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Необходимо написать функцию, которая распределяет выполнение заданных задач по n горутинам, независимо от общего количества задач. При этом процесс должен быть прерван, как только количество возникших ошибок превысит порог m, и при этом не должно оставаться работающих горутин. Если количество ошибок не превышает m, все задачи должны быть выполнены полностью.
Ответ
Нужен пул из n работников и общая отмена при ошибке номер m+1. Уже запущенные задачи должны поддерживать context, иначе гарантировать их остановку нельзя.
Явно зададим Task как функцию, возвращающую error и учитывающую отмену. Возвращаем число ошибок; при допустимом количестве задачам дают закончиться.
import (
"context"
"errors"
"sync"
)
func RunTasks(parent context.Context, tasks []func(context.Context) error,
n, m int) (int, error) {
if n < 1 || m < 0 { return 0, errors.New("invalid limits") }
ctx, cancel := context.WithCancel(parent)
defer cancel()
var mu sync.Mutex
var wg sync.WaitGroup
next, failures := 0, 0
for i := 0; i < n; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
mu.Lock()
if ctx.Err() != nil || next == len(tasks) {
mu.Unlock()
return
}
task := tasks[next]
next++
mu.Unlock()
if err := task(ctx); err != nil {
mu.Lock()
failures++
if failures > m { cancel() }
mu.Unlock()
}
}
}()
}
wg.Wait()
if failures > m { return failures, errors.New("error limit exceeded") }
return failures, parent.Err()
}
После превышения порога новые задания не выдаются; уже выданные могут закончиться с дополнительными ошибками. Возврат происходит только после остановки всех работников. Задачи должны быть ненулевыми, не паниковать и завершаться при отмене: произвольную функцию, игнорирующую context, Go принудительно безопасно не останавливает.