Используйте concurrent, когда независимые выражения могут выполняться одновременно,
а вызывающему коду требуется единая запись с именованными результатами. В обычных
прикладных программах выбирайте форму с ограничением по времени и явным резервным значением
на случай тайм-аута.
Успеваем до истечения времени
Сохраните следующий код как concurrency-success.tpz:
let результат = concurrent(timeout: 3s) {
итого: 1 + 2
метка: "ready"
} else {
{ итого: -1, метка: "timeout" }
}
print("{результат.итого} {результат.метка}")Проверьте и запустите его:
topaz check concurrency-success.tpz
topaz run concurrency-success.tpzОбе задачи завершаются до истечения тайм-аута, поэтому их имена становятся полями результата:
3 readyЗапись связывает каждое значение с именем задачи. При этом она не отражает, какая из задач началась или завершилась раньше.
Выбираем запасную ветвь при тайм-ауте
Во второй программе одна из задач не может завершиться. Сохраните код как
concurrency-timeout.tpz:
function крутиться() -> int {
let mut счётчик = 0
while true { счётчик += 1 }
счётчик
}
let результат = concurrent(timeout: 5ms) {
зависло: крутиться()
} else {
{ зависло: -1 }
}
print("{результат.зависло}")Проверьте и запустите его:
topaz check concurrency-timeout.tpz
topaz run concurrency-timeout.tpzЕсли первым истекает тайм-аут, частичные результаты задач не возвращаются, а ветвь
else предоставляет итоговый результат:
-1Различаем три исхода
| Что произошло до истечения тайм-аута | Результат выражения |
|---|---|
| Всё задачи завершились | Запись с одним полем для каждой задачи |
| Первым истёк тайм-аут | Значение блока else |
| В задаче возникла ошибка выполнения | Всё выражение завершается ошибкой, и else не выполняется |
Если задача возвращает Err(error), ошибка выполнения не возникает. Этот Result
является обычным значением в именованном поле результата. Запасная ветвь должна
иметь тип, совместимый с записью успешных задач, поэтому в обоих примерах
успешная ветвь и else используют одинаковые имена полей и совместимые типы
значений.
Чего не гарантируют имена
Имена связывают задачи с их результатами, но не задают порядок выполнения. Топаз не
определяет порядок запуска и завершения задач, порядок смешивания вывода, справедливость
планировщика или детерминированное чередование. Если порядок имеет значение, не
вызывайте print внутри задач. Сначала дождитесь общего результата и выводите
его после объединения, как показано в примерах.
Отмена и очистка ресурсов оставшихся задач после тайм-аута относятся к политике среды выполнения. Выражение Топаза не отслеживает ошибки, возникающие в оставшихся задачах после истечения тайм-аута. Не следует рассчитывать ни на конкретную реализацию планировщика, ни на переносимый механизм очистки после тайм-аута.
Частые исправления
- Пишите
3sили5msбез пробела. Обращение к свойству вроде.secondsне является литералом времени. - Форма с тайм-аутом требует наличия
else, а простое объединение не принимаетelse. - Ветвь
elseобрабатывает только тайм-аут. Она не перехватывает ошибки выполнения и не извлекает значение изErr. - Имена задач должны быть уникальными. Синтаксиса для частичного результата не предусмотрено.
Простое объединение concurrent { ... } без тайм-аута уместно на углублённой
странице, когда ожидание всех задач выступает предметом примера. В обычных
сценариях эта форма не используется по умолчанию.
В Топазе отсутствуют неявная асинхронная модель, синтаксис async/await, доступные
пользователю дескрипторы задач, общая арифметика времени и фиксированный протокол
отмены. Наблюдаемые границы ошибок и порядка выполнения описаны на странице
Поведение среды выполнения, а знакомые синтаксические формы,
которые пока не поддерживаются, — на странице
Запрещённые и отложенные формы.