Используйте concurrent, когда независимые выражения могут выполняться вместе,
а вызывающему коду нужна одна запись с именованными результатами. Для обычной
прикладной программы выбирайте ограниченную форму с явным запасным значением
на случай тайм-аута.
Успеваем до истечения времени
Сохраните следующий код как concurrency-success.tpz:
let result = concurrent(timeout: 3s) {
total: 1 + 2
label: "ready"
} else {
{ total: -1, label: "timeout" }
}
print("{result.total} {result.label}")Проверьте и запустите его:
topaz check concurrency-success.tpz
topaz run concurrency-success.tpz
Обе задачи заканчиваются до предельного срока, поэтому их имена становятся полями результата:
3 readyЗапись связывает каждое значение с именем задачи. Она не сообщает, какая задача началась или завершилась раньше.
Выбираем запасную ветвь при тайм-ауте
Во второй программе одна задача не может завершиться. Сохраните код как
concurrency-timeout.tpz:
function spin() -> int {
let mut i = 0
while true { i += 1 }
i
}
let result = concurrent(timeout: 5ms) {
stuck: spin()
} else {
{ stuck: -1 }
}
print("{result.stuck}")Проверьте и запустите его:
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, открытых
пользователю дескрипторов задач, общей арифметики времени и заданного протокола
отмены. Наблюдаемые границы ошибок и порядка описаны на странице
Поведение среды выполнения, а знакомые формы,
которые пока не поддерживаются, — на странице
Запрещённые и отложенные формы.