Структура программы

Конкурентность

Именованные задачи с ограничением времени: успех, тайм-аут, значения Result и ошибки выполнения.

Эта страница описывает Топаз v5.17. Прежде чем считать её актуальной, сверьте поле version в /version.json со значением 5.17.

Используйте concurrent, когда независимые выражения могут выполняться вместе, а вызывающему коду нужна одна запись с именованными результатами. Для обычной прикладной программы выбирайте ограниченную форму с явным запасным значением на случай тайм-аута.

Успеваем до истечения времени

Сохраните следующий код как concurrency-success.tpz:

TOPAZ
let результат = concurrent(timeout: 3s) {
    итого: 1 + 2
    метка: "ready"
} else {
    { итого: -1, метка: "timeout" }
}

print("{результат.итого} {результат.метка}")

Проверьте и запустите его:

BASH
topaz check concurrency-success.tpz
topaz run concurrency-success.tpz

Обе задачи заканчиваются до предельного срока, поэтому их имена становятся полями результата:

Вывод
3 ready

Запись связывает каждое значение с именем задачи. Она не сообщает, какая задача началась или завершилась раньше.

Выбираем запасную ветвь при тайм-ауте

Во второй программе одна задача не может завершиться. Сохраните код как concurrency-timeout.tpz:

TOPAZ
function крутиться() -> int {
    let mut счётчик = 0
    while true { счётчик += 1 }
    счётчик
}

let результат = concurrent(timeout: 5ms) {
    зависло: крутиться()
} else {
    { зависло: -1 }
}

print("{результат.зависло}")

Проверьте и запустите его:

BASH
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, открытых пользователю дескрипторов задач, общей арифметики времени и заданного протокола отмены. Наблюдаемые границы ошибок и порядка описаны на странице Поведение среды выполнения, а знакомые формы, которые пока не поддерживаются, — на странице Запрещённые и отложенные формы.