LINUX.ORG.RU

Zig 0.16 - async здорового человека

 ,


1

7

Zig 0.16 закрыл проблему раскраски функций: sync и async теперь имеют одинаковую сигнатуру, отличается только переданный I/O-интерфейс. Если вы писали асинхронный Rust и упирались в async fn-заражение - посмотрите, как это решено здесь.
async без раскраски функций - это то, на чём подрывались Rust, JavaScript и C#. Асинхронная функция ничем не отличается по сигнатуре от синхронной - меняется только переданный Io.

Ну и всякого по мелочам:

  1. «Juicy Main» это внутреннее название proposal Эндрю Келли - идея в том, что точка входа должна получать «сочный» набор готовых зависимостей, а не создавать их внутри. DI здесь значит что аллокатор, I/O, env и preopens передаются в main снаружи, а не конструируются каждым приложением заново. Раньше каждая программа на Zig начиналась с одного и того же бойлерплейта: создать GeneralPurposeAllocator, получить arg-итератор через std.process.argsAlloc, отдельно дёрнуть std.process.getEnvMap. В 0.16 всё это подаётся параметром в main
  2. В C setenv в многопоточной программе это UB: глобальная environ читается без блокировок. Zig до 0.16 наследовал эту проблему через std.os.environ, который ещё и нельзя было заполнить без линковки libc.
    Теперь окружение доступно только из main через init.environ_map. Если библиотеке нужен env - она принимает его параметром, как аллокатор. Это ломает код, дёргавший std.process.getEnvVarOwned из произвольного места, но убирает целый класс thread-safety-багов.
    Параллельно переименованы функции в std.mem: indexOf → find, добавлены cut / cutScalar для разбиения слайсов по первому/последнему вхождению.
  3. В 0.16 появился собственный ELF-линкер, он включается флагом -fnew-linker, а при -fincremental на self-hosted ELF-сборке используется автоматически. Он пока не feature-complete (например, не пишет DWARF), поэтому по умолчанию release-сборки идут через LLVM + LLD. Выгода - инкрементальная линковка (194мс → 65мс на тестовом проекте) и меньше зависимостей для debug-сборок.
  4. доработки под Windows: сетевой стек теперь работает без ws2_32.dll (напрямую через NtDll), завершена миграция с Win32 API на NtDll для остальных системных вызовов, появился inter-process progress reporting для параллельных сборок.
  5. x86-бэкенд компилятора стал самодостаточным - дебажные сборки на x86_64 собираются без LLVM и идут значительно быстрее. aarch64-бэкенд ещё work-in-progress: в 0.16 он падает на behavior-тестах.
  6. Инкрементальная компиляция переработана, меньше false-rebuilds, стабильнее на больших проектах.
  7. Fuzzer (zig test –fuzz) получил multi-process режим, infinite mode и crash dumps с AST-дампом.
  8. Build-система: локальный override пакетов, –error-style и –multiline-errors, таймауты юнит-тестов, temporary files API.
  9. Крипто: добавлены AES-SIV, AES-GCM-SIV, Ascon-AEAD, Ascon-Hash, Ascon-CHash.
  10. Heap: ArenaAllocator стал thread-safe и lock-free, обёртка ThreadSafeAllocator удалена.
  11. Тулчейн: LLVM 21 (с отключённой loop vectorization из-за регрессии), musl 1.2.5, glibc 2.43, Linux 6.19 headers, macOS 26.4 headers, MinGW-w64, FreeBSD 15.0 libc

Поздравляю разработчиков, пользователей, интересующихся и вообще - всех причастных.
Ура!

★★★★

Последнее исправление: dataman (всего исправлений: 1)

у меня маленький вопросик, Zig адептам

можно ли:

  1. написать на Zig простенькое GUI приложение (менюшки, поле ввода, кнопочки)
  2. скомпилировать его для linux(x86),osx(arm,x86),win(x86) на линукс хосте

на rust я это сделал и был удивлен что все заработало из коробки, приложение запустилось на всех 4 платформах, использовал egui

gagarin0
()
Последнее исправление: gagarin0 (всего исправлений: 1)

Тулчейн: LLVM 21

Фи, какое старьё! C3 поддерживает LLVM 19-23.

dataman ★★★★★
()
Ответ на: комментарий от gagarin0

можно ли:

Краткий ответ- можно, но.
Пафос новости как раз в том, что 0.16 - это ломающее обновление.
Поэтому zig-webgui или dvui (или что там еще) могли еще не успеть адаптироваться (не проверял) и придется потерпеть\подождать.

olelookoe ★★★★
() автор топика
Ответ на: комментарий от olelookoe

понял, а буквально в двух словах, можно узнать как будет происходить кросскомпиляция? у меня сейчас (для раста) сделано так:

build-client:linux:
  image: *rust_image
  script:
    - cargo build --release
 
build-client:windows:
  image: metacoma/rust-mingw:1.89
  script:
    - cargo build --release --target x86_64-pc-windows-gnu

build-client:x86_64-apple-darwin:
  image:
    name: joseluisq/rust-linux-darwin-builder:1.89.0
  variables:
    CC: o64-clang
    CXX: o64-clang++
  script:
    - cargo build --release --target x86_64-apple-darwin

build-client:aarch64-apple-darwin:
  image:
    name: joseluisq/rust-linux-darwin-builder:1.89.0
  variables:
    CC: oa64-clang
    CXX: oa64-clang++
  script:
    - cargo build --release --target aarch64-apple-darwin
gagarin0
()
Последнее исправление: gagarin0 (всего исправлений: 2)

Хехе акунк.

Если вы писали асинхронный Rust и упирались в async fn-заражение - посмотрите, как это решено здесь.

Гдесь? Линки нигде нет.

Вообще - нигде красивых async/await конструкций не видел, если зиг сможет их хорошо сделать - будет хорошо.

Bfgeshka ★★★★★
()

Радует что язык развивается, жаль что это очередная перманентно нестабильная игрушка одного человека, на которой прод писать не будут никогда.

anonymous
()

Хороший список изменений.

Хоть один язык в наше время разрабатывается программистом будучи в сознании.

Радует.

wandrien ★★★★
()
Ответ на: комментарий от anonymous

Ладно бы она была просто нестабильная, но с четким видением будущего. А то примерно в декабре Келли (или как его) вдруг разродился постами на тему: «Я тут понял, что async говно и набросал гениальную альтернативную концепцию. Она недоделанная, но уже мне очень нравится. Теперь резко все ломаем и будем переделывать под нее».
Не, с Io идея, безусловно, хорошая, но чего ж не раньше-то?
Получается, что у него нет цельного видения языка.

прод писать не будут никогда

В ближайшие годы точно нет. Быстрее Гугл свой карбон напишет (что идентично «когда рак на горе свистнет»). И это грустно.

anonymous
()
Ответ на: комментарий от olelookoe

Слышал, но считаю, что проблема преувеличена. Процитирую https://news.ycombinator.com/item?id=36211411

I think the view of asynchronous functions as «upwardly infectious» comes from focusing too much on JavaScript.

Async/Await arguably[1] first debuted on C#, and in C# you could always call Task.Wait() or Task.Result to block on the Task returned from the code. Similarly, Python async coroutines can be run from blocking functions using event_loop.run_until_complete(coroutine). Kotlin similarly has runBlocking(). Running async code from blocking code is also possible on Rust, but it depends on your async runtime (tokio, async_std, etc.). JavaScript/TypeScript is the only mainstream language which completely disallows calling async from blocking code, and that is only due to its single-threaded (mostly) never-blocking design.

That doesn't mean you should always feel free to call asynchronous functions from synchronous ones. For instance, if you have a limited number of synchronous threads, this could be a bad idea. Likewise, if you call an async function that calls a synchronous function that then calls an asynchronous function again — you're likely in for trouble. So asynchronous functions are upwardly infectious in a way: You can call them from synchronous function, but in many (or even most) cases it is not a good idea to do so.

Вообще конверторы с асинхронного API на синхронное и обратно (тупо через создание потока) вроде как никогда не были проблемой. Ещё до появления async/await синтаксиса.

MirandaUser2 ★★
()
Ответ на: комментарий от Psilocybe

А почему ви отвечаете вопросом на вопрос?

у нас такая тгадиция, а шо такое?

olelookoe ★★★★
() автор топика
Ответ на: комментарий от hippi90

Talk is cheap. Show me the code. (c)

почему бы и не посмотреть тот же bun, например.

olelookoe ★★★★
() автор топика
Ответ на: комментарий от gagarin0

а буквально в двух словах, можно узнать как будет происходить кросскомпиляция?

если в двух словах тогда так:

Компиляция программы для 64-битной ARM-платформы под Linux:
zig build-exe .\tiny-hello.zig -O ReleaseSmall -fstrip -fsingle-threaded -target aarch64-linux

Сборка программы под Windows:
zig build-exe main.zig -target x86_64-windows

Zig поддерживает различные архитектуры процессоров (x86_64, ARM, aarch64, i386, riscv64, wasm32) и операционные системы (Linux, macOS, Windows, freebsd, netbsd, dragonfly, UEFI). Список поддерживаемых целей постепенно расширяется.

Для получения информации о доступных целевых платформах можно использовать команду zig targets

olelookoe ★★★★
() автор топика
Ответ на: комментарий от MirandaUser2

Вообще конверторы с асинхронного API на синхронное и обратно (тупо через создание потока) вроде как никогда не были проблемой. Ещё до появления async/await синтаксиса.

Ну-ну. А потом выясняется, что супер-мега сервис на Go прекрасно работает на многоядерной машинке разработчика и встаёт колом на двуядерной малышке. Ибо никаких сене-желто-красных функций там не видно.

AlexVR ★★★★★
()
Ответ на: комментарий от MirandaUser2

Вообще конверторы с асинхронного API на синхронное и обратно (тупо через создание потока) вроде как никогда не были проблемой.

А для меня были. Причем в даже в новомодном dart. Надоели все эти ритуальные приседания.

olelookoe ★★★★
() автор топика
Ответ на: комментарий от olelookoe

очень интересно, т.е. я смогу собрать бинарник (который использует UI) для платформы arm, под ОС macOS, под линукс без лишних телодвижений?

gagarin0
()
Ответ на: комментарий от gagarin0

т.е. я смогу собрать бинарник (который использует UI) для платформы arm, под ОС macOS, под линукс без лишних телодвижений?

В теории да, ничто не мешает. Но на практике - надо попробовать и потом с возмущением рассказать коллегам как оно чо.

olelookoe ★★★★
() автор топика
Ответ на: комментарий от anonymous

Получается, что у него нет цельного видения языка.

Ни у кого никакого «цельного видения языка» нет и никогда не будет, слишком обширная область. Абсолютно нормально что язык ломают (ломают и питон и rust, а что не ломают - либо стагнирует как go, либо обрастает раковыми опухолями как плюсы). Просто есть языки ориентированные на использование, а есть ориентированные исключительно на эксперименты, и zig относится к последним. Писать на нём глупо, ибо код через год перестанет собираться, можно просто потырить идеи которые выстрелили и закопать.

В ближайшие годы точно нет. Быстрее Гугл свой карбон напишет (что идентично «когда рак на горе свистнет»). И это грустно.

А чего тут грустного? Языки предназначенные для игрулек не вылезают из игрулек, предназначенные для помойки идут на помойку, языки предназначенные ни для чего никогда и не взлетят.

anonymous
()
Ответ на: комментарий от greenman

опечатка для привлечения внимания?

а не надо привлекать внимание к привлечению внимания!

olelookoe ★★★★
() автор топика

async без раскраски функций - это то, на чём подрывались Rust, JavaScript и C#. Асинхронная функция ничем не отличается по сигнатуре от синхронной - меняется только переданный Io

Какой прорыв. Когда столкнусь с проблемой раскраски функций, сразу брошу rust и побегу всё переписывать на zig.

идея в том, что точка входа должна получать «сочный» набор готовых зависимостей, а не создавать их внутри

Шикарно. Так додумается что io и аллокатор можно глобальными делать.

anonymous
()

Zig 0.16 закрыл проблему раскраски функций: sync и async теперь имеют одинаковую сигнатуру, отличается только переданный I/O-интерфейс. Если вы писали асинхронный Rust и упирались в async fn-заражение - посмотрите, как это решено здесь.

ничего он не закрыл, лол. Просто теперь цвет функции будет определяться не специальным ключевым словом в сигнатуре, а наличием специального параметра, вот этим самым I/O-интерфейсом.

И получается ровно то же самое что раньше: если у тебя функция foo() не цветная, а bar(io) цветная, то вызвать bar из foo ты не сможешь, потому что в foo() у тебя не будет этого самого io. Придется либо создавать его на месте, либо передавать откуда-нибудь сверху отдельным параметром, делая foo() цветной. Это ровно то же самое асинк-заражение что и раньше.

Реальный способ бороться с этим был, есть и будет только один: явно обрабатывать частичные чтения и прочие EAGAIN и писать эвент-лупы с машинами состояний и потоковыми парсерами. Сложно, да. И сразу становится видно, какое непродуманное гуано все эти сетевые протоколы и прочие JSON. Но тут уже надо определиться, либо ты программист, либо нет.

Lrrr ★★★★★
()
Последнее исправление: Lrrr (всего исправлений: 1)
Ответ на: комментарий от anonymous

Ни у кого никакого «цельного видения языка» нет и никогда не будет, слишком обширная область.

Ядро языка не должно меняться от релиза к релизу так, что «hello world», собиравшийся в предыдущей минорной версии перестает не собираться в новой минорной.

а что не ломают - либо стагнирует как go

Это как раз и называется «стабильность» и «цельное видение», которых якобы ни у кого и никогда нет.

либо обрастает раковыми опухолями как плюсы

А вот тут Zig и С++ чем-то похожи. Если бы из С++ вовремя удаляли «опухоли», наплевав на обратную совместимость, из него вполне получился бы Zig.

А чего тут грустного? Языки предназначенные для игрулек не вылезают из игрулек, предназначенные для помойки идут на помойку, языки предназначенные ни для чего никогда и не взлетят.

По началу была надежда что этот Келли действительно хочет сделать нечто большее, чем язык для постоянных экспериментов.

Надежда стремительно улетучилась, но воспоминания о ней остались.

anonymous
()
Ответ на: комментарий от Lrrr

Просто теперь цвет функции будет определяться не специальным ключевым словом в сигнатуре, а наличием специального параметра,

Казалось бы, ну очевидная же мысль.

anonymous
()
Ответ на: комментарий от greenman

В заголовке опечатка для привлечения внимания?

Да, исправьте на:

Zig 0.16 - anyc здорового человека

AUX ★★★★
()

sync и async теперь имеют одинаковую сигнатуру, отличается только переданный I/O-интерфейс

Наконец-то в Zig изобрели монады!

anonymous
()
Ответ на: комментарий от anonymous

Радует что язык развивается, жаль что это очередная перманентно нестабильная игрушка одного человека, на которой прод писать не будут никогда.

У меня есть софтина, которой пользуюсь ежедневно и которая написана на сабже. Я про ghostty.

Loki13 ★★★★★
()
Ответ на: комментарий от Lrrr

И получается ровно то же самое что раньше: если у тебя функция foo() не цветная, а bar(io) цветная, то вызвать bar из foo ты не сможешь, потому что в foo() у тебя не будет этого самого io.

Я конечно на сабже не писал, но, разве в новости не сказано о том, что и в foo и в bar всегда должно передаваться io, только передаваться может разное. Ну это как я понял новость. По ссылкам не ходил, код не смотрел, от заражения в C# раздражался.

Loki13 ★★★★★
()
Последнее исправление: Loki13 (всего исправлений: 2)
Ответ на: комментарий от olelookoe

А для меня были. Причем в даже в новомодном dart. Надоели все эти ритуальные приседания.

Гм, ну тогда это проблема Dart. А в тексте новости ты почему-то пишешь про Rust, JavaScript и C#.

Смотрю примеры из https://andrewkelley.me/post/zig-new-async-io-text-version.html и не совсем понимаю одну вещь:

fn juicyMain(gpa: Allocator, io: Io) !void {
    _ = gpa;

    var future = io.async(doWork, .{io});

    future.await(io); // idempotent
}
Зачем в future.await передается io? Разве это может бы какой-то другой Io, кроме как из io.async?

MirandaUser2 ★★
()
Ответ на: комментарий от MirandaUser2

Ну вот, как я и говорил. У DoWork всегда есть io в параметрах, а вызовешь ты его синхронно Dowork(io) или io.async(Dowork), это уже как захочешь.

Lrrr

Т.е. получается, что функции всегда цветные, отличается только способ вызова.

Loki13 ★★★★★
()
Последнее исправление: Loki13 (всего исправлений: 1)

async без раскраски функций

Если в обществе нет цветовой дифференциации функций — то нет цели!

Nervous ★★★★★
()
Ответ на: комментарий от Loki13

Разделение на обычные функции и асинхронные в безстековых корутинах выбрано не просто так, а потому асинхронные функции являются объектом со стейт машиной и фреймом функции, ну и каким-то методом, который непосредственно будет выполняться.

Если зиг компилирует функцию только в одном виде и ее можно просто вызывать внутри обычных функций, значит это не безстековая корутина, а обычная функция с полноценным стеком, может быть и управляемая юзер спейс скелулером, но это уже детали.

Фактически нормальных корутин в зиге нет

Darfin
()

В расте несколько лет назад шли разговоры о том, чтобы признак асинхронности считался чем-то типа обычноно параметра у дженерик функции.

https://blog.rust-lang.org/inside-rust/2023/02/23/keyword-generics-progress-report-feb-2023/

Вот если бы эти исследования завершились успешно, это было бы глобальное изменение в подходе.

Ты объявляешь дженерик функцию со специальным синтаксисом и в зависимости от того, в каком контексте ты ее используешь она бы компилировалась или как асинхронная или как обычная стековая функция.

Но уже три года как вестей по этому поводу нет, видимо, нашлись какие-то нерешаемые проблемы.

Сейчас в зиге ничего даже близко подобного нет, как впрочем и в расте. Но зато в расте есть вполне себе юзабельные безстековые корутины, которые используются чуть ли не в каждом втором проекте.

Darfin
()

А в стековых корутинах в принципе нет никаких цветов, любую функцию можешь вызывать из любой как это делается в том же голанге. Если в зиге ушли от безстековых корутин, то и у них не должно быть проблем, тоже мне достижение

Darfin
()
Ответ на: комментарий от Lrrr

писать эвент-лупы с машинами состояний

Иначе говоря, компилировать асинк функции руками, а не компилятором.

quantum-troll ★★★★★
()
Ответ на: комментарий от olelookoe

Но это перевод статьи, из которой я взял пример :-(

Вообще судя по https://kristoff.it/blog/zig-new-async-io/ проблемы раскраски функций в ziglang изначально не было (на уровне исходного кода).

The famous “What Color is Your Function?” blog post by Bob Nystrom explains very well the issues that come from the virality of async functions. In other languages it’s common to see a blocking and an async variant of the same thing (e.g. a database client), each maintained by different authors.

Zig has solved this problem since the beginning, as I previously explained in “What is Zig’s Colorblind Async / Await”. Thanks to Zig’s clever (and unorthodox) usage of async and await, a single library can work optimally in both synchronous and asynchronous mode, achieving the goal of code reusability, a property preserved with this new iteration of async I/O.

But this new approach pushes color blindness even further: previously the source code would be free from the virality of async/ await, but at runtime the program was still forced to use stackless coroutines, which have a viral calling convention. Now io.async and Future.await can be used with a variety of execution models, from blocking to stackless coroutines, fully freeing you from any form of virality.

MirandaUser2 ★★
()
Ответ на: комментарий от MirandaUser2

Но это перевод статьи, из которой я взял пример :-(

упс. невнимательность наше всё.

проблемы раскраски функций в ziglang изначально не было

Да, но за счет того что «at runtime the program was still forced to use stackless coroutines».

А теперь «io.async and Future.await can be used with a variety of execution models, from blocking to stackless coroutines, fully freeing you from any form of virality», вот в чем пойнт.
Т.е. не прибить гвоздями к «единственно правильному решению», а дать работать с любым решением, при этом не пугая разработчика многообразием специальных подходов для каждого из решений.

olelookoe ★★★★
() автор топика
Ответ на: комментарий от Darfin

Если зиг компилирует функцию только в одном виде и ее можно просто вызывать внутри обычных функций,

Он может выбирать как её компилировать, во время компиляции, увидев как она используется. Может даже скомпилировать её 2 раза. Заражение оно же не для компилятора противно, а для разработчика.

Loki13 ★★★★★
()
Ответ на: комментарий от Loki13

Он может выбирать как её компилировать, во время компиляции, увидев как она используется. Может даже скомпилировать её 2 раза.

Где-нибудь есть четкое описание, как это происходит? Готовый пример? Чтобы можно было создать, например, 10к корутин и увидеть, что оно не выжрало гигабайты памяти.

Darfin
()
Ответ на: комментарий от Darfin

Я дочитал https://kristoff.it/blog/zig-new-async-io/

Безстековых корутин нет, сейчас есть только стековые. Безстековые появятся когда-нибудь в светлом будущем и как-то будут волшебным образом работать. Ну вот когда заработают тогда и можно будет оценивать. А в стековых корутинах, еще раз повторю, никогда не было проблем с цветами, поэтому их и не может быть в текущей реализации зига.

Darfin
()
Ответ на: комментарий от Darfin

10к корутин и увидеть, что оно не выжрало гигабайты памяти.

А почему 10к корутин не должны потреблять память и какое это отношение имеет к цветности функций?

r--r--r--
()
Ответ на: комментарий от Darfin

А в стековых корутинах, еще раз повторю, никогда не было проблем с цветами

Ещё как есть. Reqwest паникует при блокирующем вызове из асинка.

r--r--r--
()
Последнее исправление: r--r--r-- (всего исправлений: 1)
Ответ на: комментарий от Darfin

Безстековые появятся когда-нибудь в светлом будущем

Так, пажди, ты что имеешь в виду?

Stackful корутины:

Эти корутины имеют собственный стек. Это значит, что сами корутины управляют своим выполнением, а не зависят от операционной системы. Благодаря наличию собственного стека, такие корутины могут хранить больше информации: они запоминают не только текущее состояние функции, но и иерархию вложенных вызовов других функций, которые были вызваны внутри этой корутины. Это позволяет, например, приостановить выполнение одной корутины на любом уровне вызова функций и передать управление другой корутине.

Stackless корутины:

В отличие от stackful корутин, stackless корутины не имеют собственного стека. Их выполнение управляется как машина состояний (state machine), которую генерирует компилятор. Это выглядит так, как будто выполнение функции просто переключается между разными состояниями - например, между ожиданием данных и продолжением выполнения после их получения.

На практике stackless корутины чаще всего реализуются через ключевые слова вроде async/await (Превед из светлого будущего!). Когда функция встречает await, она приостанавливается до тех пор, пока не будет готов результат, после чего продолжает выполнение.

А ты про что?

olelookoe ★★★★
() автор топика
Последнее исправление: olelookoe (всего исправлений: 1)

блин, кто-то взял и поправил кликбейтный заголовок, добрая душа

olelookoe ★★★★
() автор топика
Ответ на: комментарий от anonymous

Ядро языка не должно меняться от релиза к релизу так, что «hello world», собиравшийся в предыдущей минорной версии перестает не собираться в новой минорной.

Ну, например, все строки и вызовы print могут сломаться?

Это как раз и называется «стабильность» и «цельное видение», которых якобы ни у кого и никогда нет.

Нет, это называется стагнация, тут эти понятия не применимы - язык как-то там был спроектирован, написан и больше не меняется. А нормальные языки развиваются.

А вот тут Zig и С++ чем-то похожи. Если бы из С++ вовремя удаляли «опухоли», наплевав на обратную совместимость, из него вполне получился бы Zig.

Zig с C++ вообще нельзя сравнивать, он слишком низкоуровневый. Только с C.

anonymous
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.