LINUX.ORG.RU

Каковы характеристики взаимодействия с stdout дочернего процесса?

 ,


0

2

Предистория

У меня возникла потребность писать скрипты не на таких скриптовых языках как bash, потому что мне не нравилась не полнота возможностей и подводные камни в нём, вместе со сложной документацией. Я начал искать альтернативы, нашёл nushell, избавление от подводных камней обеспечилась, потому что это современная оболочка, но не полнота возможностей, и незадокументировать некоторых вещей может приводить к неожиданностям. Потом до меня дошло что можно использовать любой язык программирования, всё что мне нужно это библиотека для вызова дочерних процессов, для меня это казалось магией, которой обладают лишь командные оболочки. Ну я выбрал rust, там как раз ещё и с оффициальной документаций всё в порядке. Но потом я выбрал node.js, потому что там прототипы, и мне кажеться это очень гибко, и не надо с типами шаманить. Меня на node перенял zig с его гибкой системой типов. Но zig нестабилен, поэтому пока оверхедные но доступные альтернативы, по типу node, может есть лучше, но я не нашёл

Суть вопроса

Я знаю что есть различные методы ipc. Я так понимаю stdout особо не считается за ipc, потому что stdout/stdin это просто файлы. Так вот мне интересно, можно ли организовать нормальное «одностороннее» ipc. Под односторонним я понимаю изменения в коде только родительского процесса. А дочерний лишь иногда пишет в stdout и через некоторое время завершается. Под нормальным я подразумеваю производительное. Ну то есть, если я правильно понял, stdout это файлы, а значит там идёт оверхед от записи и чтения с диска?
А ещё меня интересует как получать оповещение для родительского процесса, когда дочерний что-то написал в stdout. Просто в стандартной библиотеке rust можно читать из stdout только когда процесс завершен, а я например видел, что есть же такие процессы, как архиваторы, и они на протяжении своей работы выводят прогресс выполненной операции. Когда я спросил про это, мне порекомендовали крейт mio, там я познакомился с epoll, это такая штука, которая позволяет получать от ОС оповещение когда в stdout, то есть в файл, была произведена запись и можно читать новые данные
Когда я спросил как работает в Node.js child.stdout.on("data", ... и какой метод оповещения используется в случае с stdout, мне сказали что я дурак и вообще спрашиваю какую-то чушь. Я ведь знаю что кроме epoll есть poll, select. А на windows и mac os ещё другие методы, ведь это платформозависимая вещь.



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

значит там идёт оверхед от записи и чтения с диска?

Идиома «всё есть файл» говорит, не о том, что это физически сохранённый на диск файл. Это относиться только к способу общения.

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

А ещё меня интересует как получать оповещение для родительского процесса, когда дочерний что-то написал в stdout.

похоже на твоё недопонимание.

В независимости от языка, схема приблизительно такая.

  1. Процесс А вызывает библиотечную функцию, которая запишет данные данные в буфер процесса (управляемый, например, стандартной библиотекой ЯП).
  2. Библиотечная функция при наступлении того или иного события вызовет функцию ОС. (Например, таким событием, может быть символ \n в данных)
  3. ОС переместит данные в свой буфер. Если он переполнен, то может и приостановить процесс А.
  4. Процесс Б запросит данные у ОС.
  5. Если есть данные, то ОС скопирует их из своего буфера в буфер процесса Б. Либо, может, приостановить работу процесса Б.
AlexVR ★★★★★
()

Ты отчасти прав, stdin и stdout в реальности это файлы, но объявляются как потоки данных, а stdin и stdout - это ссылки (файловые дескрипторы) на эти файлы, которые читает командная оболочки или другой процесс.

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

Не совсем понятно что ты пишешь про получение оповещения от родительского процесса, когда дочерний что-то написал.

Зачем тебе это нужно?

К примеру в linux есть команда trap, ловушка, вот пример на bash:

#!/bin/bash

var1="234"


function main() {
  while true ; do
    echo PID: $$ - $var1
    sleep 3
  done
}


function read_env() {
 . .env
}

trap "echo trapped; read_env" SIGUSR1

main

Здесь объявляется функция main, в ней цикл с выводом PID, значения переменной var1 и ожиданием в 3 секунды.

Ниже ставится ловушка, которая будет срабатывать ко сигналу USR1.

Далее вызов функции main.

В файле .env задаётся другое значение переменной:

cat .env
var1="123"

Пример работы:

./trap.sh
PID: 2803676 - 234
PID: 2803676 - 234
PID: 2803676 - 234
PID: 2803676 - 234
trapped
PID: 2803676 - 123
PID: 2803676 - 123

Командой kill подаётся сигнал:

kill -USR1 2803676

Срабатывает trap и выполняется то, что указано делать по ловушке.

Как видишь, изменилось значение переменной, она считалась из .env файла.

Можешь пробовать делать что-то такое.

Но вообще, моё мнение, ты вместо того, чтобы разобраться как использовать инструмент, который есть везде, а bash или sh есть везде, полез поверхностно изучать кучу новых для тебя вещей, которые ещё нужно ставить, если ты будешь написанное тобой где-то использовать ещё кроме твоего ПК.

Ещё есть ionotify.

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

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

На счёт оверхеда понятно, я так и подозревал что stdio это не настоящие файлы. Но я не понял 4 пункт на счёт уведомлений:

Процесс Б запросит данные у ОС.

Что значит запросит? А откуда я буду знать когда программа архиватор обновила счётчик процента в своём прогрессбаре, отображаемом в stdout? То есть как я буду знать когда запрашивать надо? Мне что, запрашивать данные каждую милисекунду, и проверять не изменились ли они? Мне кажеться это и есть оверхед. Вдруг архиватор обрабатывает ну очень большие файлы и там процент обновляется ну раз в 5 минут, а я каждую милисекунду буду проверять stdout, чтобы максимально быстро отобразить это в консоли? Мне кажеться для этого epoll был и нужен, потому что можно повесить calback или что-то типо того, когда новые данные пришли. И где тут моё недопонимание?

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

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

Я уже писал что выбирал инструмент исходя из моих потребностей, а то что кому-то что-то ставить надо меня не волнует. В любом случае все же ставят себе ОС чтоб выполнять другие программы, мне ОС не хватило, поэтому я взял ещё и рантайм node. В критическом случае можно программу на node.js в один исполняемый файл перконвертировать, правда файл будет большой, потому что там целый рантайм node, но всё же как вариант для простоты использования

А на счёт уведомлений в моём предидущем коментарии написано ещё раз, может понятнее будет

Trame
() автор топика

Вот почему мне вместо того чтобы помочь в моих заблуждениях ставят знак клоуна? Я думал только в той группе по node.js агро такие. Где мне найти нормальный форум блин? Я же ещё специально написал предисторию, чтобы можно было понять откуда такие заблуждения могли возникнуть, но нет, мне даже на эти заблуждения конструктивно не отвечают, а просто унижают, надоело

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

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

Т.е просто пишешь:

loop {
  input_data = read_data()
  output_data = work(input_data)
  show_status()
  write_data(output_data)
}
AlexVR ★★★★★
()
Ответ на: комментарий от Trame

Пример.

use std::io::Read;

fn main() {
    let mut buf = vec![0u8; 1024 * 1024];
    let mut count = 0;
    let mut start_time = std::time::Instant::now();
    loop {
        let c = std::io::stdin().read(&mut buf).unwrap();
        if c == 0 {
            break;
        }
        let end_time = std::time::Instant::now();
        let dt = end_time - start_time;
        count += c;
        println!("Readed {c} bytes in {dt:?} total {count}");
        // Work with buf
        start_time = end_time;
    }
    println!("The end");
}

cat /dev/urandom | gzip | ./simple_read
Readed 65536 bytes in 13.180265ms total 10551296
Readed 65536 bytes in 112.832µs total 10616832
Readed 65536 bytes in 99.773µs total 10682368
Readed 65536 bytes in 36.119µs total 10747904
Readed 65536 bytes in 12.108863ms total 10813440
Readed 65536 bytes in 66.262µs total 10878976
Readed 65536 bytes in 50.422µs total 10944512
Readed 65536 bytes in 47.03µs total 11010048
Readed 65536 bytes in 11.862291ms total 11075584
Readed 65536 bytes in 32.915µs total 11141120
Readed 65536 bytes in 31.938µs total 11206656
Readed 65536 bytes in 32.48µs total 11272192
Readed 65536 bytes in 12.846433ms total 11337728

Внутри std::io::stdin().read происходит вызов функции ОС.

В этот момент работа процесса останавливается и работать начинает ОС. ОС решит когда продолжить работу процесса и сколько передать данных ему.

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

Понятно теперь, что и не существовало нормального асинхронного способа чтенияи Я и крейт mio перечитал, там оказывается SourceFd в качестве источников ивентов не принимает любой файловый дескриптор. И epoll видимо было указано в той документации про другое, я так не понимаю что это… Ладно, это долгая история.
Я прочитал в доке node что там создаються pipe-ы. Для меня сложно искать информацию по всему эту ipc. Хотелось бы понять, а как там реализуеться чтение и запись? Я еле-еле понял из чтива, что используються атомики, а самый главный подводный камень — это то что stdio ограничен в размере, и если что, то просто неожиданно рухнет программа. Даже уже и не помню где прочитал, потому что куча вкладок, ничё не понятно. Как в случае взаимодействие через stdio реализуеться безопасное чтение и запись? Или в этом нет необходимости, потому что записанное нельзя изменить? Или всё-таки там что-то синхронхронизируеться? А если синхронизируеться то получаеться когда я начинаю читать, а дочерний процесс хочет писать в stdout, то child process блокируеться?

А ещё так и не было ответа на вопрос, можно ли односторонне изменить метод ipc, потому что в node группе мне сказали что через stdout взаимодействие такое себе. А что делать если изменить код дочернего процесса нельзя? Нельзя как-то подменить для него запись в stdout?

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

можно ли односторонне изменить метод ipc, потому что в node группе мне сказали что через stdout взаимодействие такое себе. А что делать если изменить код дочернего процесса нельзя?

Что означает «изменить метод ipc» и как ты собираешься его менять, если ответ от дочернего процесса не меняется?
А вообще обмен через stdout неудобен! А если процессы на разных компах будут - переписывать обмен? А если сообщение нужно послать множеству дочерних процессов? Лучше сеть использовать для обмена и один из стандартных протоколов сериализации.

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

Я думал только в той группе по node.js агро такие

nodejs повреждает мозг того, кто им пользуется. Беги пока не поздно. Лучше всего писать на Си, но некоторые почему-то его боятся.

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

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

firkax ★★★★★
()

Когда я спросил как работает в Node.js child.stdout.on(«data», ... и какой метод оповещения используется в случае с stdout, мне сказали что я дурак и вообще спрашиваю какую-то чушь. Я ведь знаю что кроме epoll есть poll, select. А на windows и mac os ещё другие методы, ведь это платформозависимая вещь.

внутри Node.js вроде как https://libuv.org/ в ответе

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

Так я ведь писал, я не могу изменить код дочернего процесса. Нельзя так нельзя, я хотел узнать что нельзя. Не спорю что через stdout не удобно, но дочерний exe не доступен для правки, так что выбора у меня нет

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

внутри Node.js вроде как https://libuv.org/

То есть это ответ на вопрос как реализованно асинхронное чтение? Я знаю что libuv позволяет через новые потоки делать блокирующее I/O неблокирующим. Получаеться если я открою какой-то интерективный процесс, как интерпретатор, то мой процесс зависнет, потому что другой поток ожидает от интерпретатора ещё вывод?

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

Вместо того чтоб нормальным русским языком, без всяких заумностей, обьяснить что ты хочешь

Хорошо, вот концентрат: Я хочу в идеале понять как это работает, но статьи про это какие-то поверхностные. Если про все методы ipc брать, то ещё поверхностнее. А если только про pipe-ы, то до сих пор мне не понятно, как там это синхронизация работает, что за ограничение на размер pipe-а, а если прочитать из pipe-а размер уменьшить и снова писать можно будет? Анонимные от именованных чем-то отличаються? Я хочу понимать всё это чтоб делать соответсвующие выводы о рациональности использования и возможностях оптимизации
Я вот например изучил полностью тему как работает 3d, ну изометрическое только, понял как работают изменения поворота, позиции и размера объектов. И сделал вывод что обьект может быть не только статическим, но и ещё просто не вращаюимся, только увеличивающимся, то есть статичный в чём-то одном. И если бы я не разобрался сам в 3d, такой возможности оптимизации я бы не увидел, потому что в движках только полную статичность можно использовать

Trame
() автор топика

может ну их нафик все эти статьи и Node.js, а просто школу закончить ? ВУЗ ставит мозги на место..

пока логика на уровне дет.сада к сожалению. Дикий недостаток системного образования, поэтому какой-то сумбур.

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

Я хочу в идеале понять как это работает, но статьи про это какие-то поверхностные

Потому что там нечего объяснять, всё тривиально.

все методы ipc брать

ipc это общее слово, оно самоценного смысла не имеет.

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

pipe это такой скользящий буфер, в который можно дописывать байты в конец с помощью сисколла write(), и забирать байты из начала с помощью сисколла read(). Если read() вызван а байтов нет - он ждёт, пока их кто-то запишет. Если вызван write() а места нет - то он ждёт пока кто-то сделает read() чтоб освободить место. Какой конкретно размер у этого буфера обычно не уточняют, полагаться на какие-то конкретные числа нельзя, вплоть до того что где-то он может оказаться 0-байтовым (то есть write должен сразу отдать данные вызванному кем-то ещё read-у, иначе ждёт).

Узнать, есть ли в пайпе байты и есть ли место можно с помощью сисколлов select(), poll() и epoll(linux)/kqueue(bsd), первый самый совместимый (есть во всех юниксах за последние 40 лет), второй самый простой, последнее самое эффективное то лучше не забивай им себе пока голову.

Анонимные от именованных чем-то отличаються?

Очевидно, тем что у анонимных нет имени, а у именованных есть. Зная имя, если оно есть, к нему может подключиться другая прога.

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

Я вот например изучил полностью тему как работает 3d
...
сделал вывод что обьект может быть не только статическим, но и ещё просто не вращаюимся

Погоди, ты вот этот вывод про объект не мог сделать без полного изучения 3д?

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

Ну пока я разбирался с матрицами, зачем они вообще существуют… Ну я же сказал полное изучение только изометрического 3d, есть же ещё другое, специальное для генерации облаков всяких и подобных тел

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

ставят знак клоуна

Не обращай внимание. Думаю, дело в том, что твоё сообщение ну очень не концентрированное и длинное. Пока читаешь к концу, забываешь, что было в начале, и в чём, собственно, сам вопрос. Поработай чуть-чуть над тем, как форумлируешь вопросы. Так и тебе будет легче найти помощь, и людям легче тебе помочь.

а просто унижают, надоело

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

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

Что такое stdin/stdout?

С точки зрения процесса, просто файлы. Один только для чтения, другой только для записи. Есть ещё stderr, который как stdout, но чтобы ошибки писать и по умолчанию не буфферизуется (об этом позже)

Обычно это просто ввод и вывод консольки. Туда юзер тык-тык, а сюда юзер зырк-зырк. Но это не правило, а просто частный случай. Опять же, это просто файлы. Ещё точнее, файловые дескрипторы.

Что такое файл?

Файл это абстракция. Файл может быть на диске, а может быть и в памяти. А может вообще никакого файла не быть, но это структура ведёт себя ну прям как файл.

С этого момента и далее воспринимай это слово так и дальше.

Что такое pipe?

Вот у тебя есть процесс А и процесс Б. Они невероятно хотят общаться.

И есть ещё такая кишка, пайп, в которую можно засунуть текст (или поток байт) на вход и получить на выходе.

При этом вход выглядит как один файл, только для записи, а выход как другой файл, только для чтения. Ну и всё.

Pipe расшифровывается как pipeline, то есть конвейерная лента.

А что такое оператор пайпа в bash?

Ничего он особенного не делает, просто берёт stdout одного процесса и пишет в stdin другого.

apt search python | grep pip — значит ты вызываешь апт и просишь найти пакеты с именем пайтон. И выводит это, как правило, в консоль. Но на самом деле, этот stdout оказывается в stdin программы греп и она начинает с этими данными тоже что-то своё делать.

А если ты просто вызовешь grep pip, сможешь сам писать ему какие-то строки. В ответ он выведет только те, в которых есть нужная подстрока.

Менее наглядный, но более точный ответ уже написали тут до меня.

Просто в стандартной библиотеке rust можно читать из stdout только когда процесс завершен

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

Дело в том, что запись в любой файл, в том числе в stdout может буфферизоваться. Это делается ради оптимизации.

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

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

Чтобы вывести прямо и здесь и сейчас, обычно есть какой-нибудь fflush или fsync. Плюс, оно, конечно, неявно происходит при завершении работы.

Я НЕ УВЕРЕН, какие есть ограничения у стандартной библиотеки Rust. Тем более, это ещё и очень сильно зависит от вызываемой программы.

Как сделать пайп в (имя языка)?

Тут читай доки. Ссылки и какие-то примеры вроде тоже кто-то привёл.

Считаются ли пайпы IPC

Да, самый базовый.

Как сделать, чтобы когда архиватор делает вжыньк прогрессбаром и я это детектил? 🤓

В идеале никак. Такую жуть парсить зачем? Лучше возьми библиотеку-архиватор, попроси её заархивировать и проверяй напрямую. Так вкуснее и менее муторно.

Я всё равно очень хочу! Или не имею другого выбора.

  1. В вызываемой программе создаёшь пайп. Получишь два файловых дескриптора, на одном конце у тебя чтение r, а на другом запись w.

  2. Вызови fork, то есть создай копию процесса.

  3. В дочернем закрой r — тыж пишешь, а не читаешь)

  4. В дочернем сделай dup2(w, fileno(stdout)) — то есть сделай так, чтобы дескриптор w склонировался и заместил собой stdout. fileno(stdout) это чтобы получить сам файловый дескриптор.

  5. В дочернем закрой w — он же после этого никуда не пропал!

  6. Вызови exeс и запусти искомую программу. Дескрипторы файлов уже подменены, а она, дура, ничего и не поймёт.

Как бэ, всё, profit. Это я на уровне системных вызовов Linux. Если хочешь стандартной библиотекой какого-либо языка, поищи доки, где-то оно должно быть.

Анонимные от именованных чем-то отличаються?

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

Вкратце — нет.

И то, и то один и тот же файл.

Только анонимный пайп это просто два файловых декриптора, два номера, два идентификатора.

А именованный это то же самое, но ещё и делает вид, что оно прям в натуре файл в дереве файловых систем.

Вон если у тебя одна из программ умеет принимать только файлы, а другая умеет работать только с stdin/stdout — ты можешь их объединить именованным пайпом.

Одно думает, что пишет в сонсольку, а другое думает, что читает из файла — все счастливы и никто не подозревает, что на самом деле они работают с общим пайпом.

А можно ли в пайп сразу и читать, и писать?

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

Хорошо, вот концентрат: Я хочу в идеале понять как это работает, но статьи про это какие-то поверхностные. Если про все методы ipc брать, то ещё поверхностнее.

Есть и норм статьи, просто надо в голове объединять информацию.

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

P.s. Когда диды завещали «всё есть файл», они, на самом деле, имели в виду, что всё есть реализация абстрактного интерфейса «файл». То есть всё унифицированео и поддерживает файловые операции. Изнутри это далеко не обязательно файл. Но ты можешь с ним работать как с файлом и полноправно делать вид, что кроме файла это ничем другим быть не может.

witaway
()
Последнее исправление: witaway (всего исправлений: 6)
Ответ на: комментарий от Trame

Ну пока я разбирался с матрицами, зачем они вообще существуют…

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

А так, вот эти все матричные формулы при раскрытии превращаются в куда менее мистические обычные. Где-то в тырнетах есть примеры.

Мне до курса университета было местами проще понять обычную форму записи, и она сама, если подумать, приходила в голову. А матричная казалась мистикой…

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

Понятно теперь, что и не существовало нормального асинхронного способа чтения

Хочешь асинхронного чтения, вот:

use tokio::io::{AsyncReadExt, AsyncWriteExt};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut stdin = tokio::io::stdin();
    let mut stdout = tokio::io::stdout();

    let mut buf = vec![0; 1024 * 1024];
    let mut count = 0;
    let mut time_start = std::time::Instant::now();

    loop {
        let n = stdin.read(&mut buf).await?;
        let time_end = std::time::Instant::now();
        let dt = time_end - time_start;
        time_start = time_end;
        if n == 0 {
            break;
        }
        count += n;
        stdout
            .write_all(format!("read {n} in {dt:?} total {count}\n").as_bytes())
            .await?;
    }

    Ok(())
}

Хочешь понять как работает. Раздели на два понятия: «чтение» и «асинхронное».

сокеты, каналы, файлы - это всё системные объекты, к которым есть доступ через системные вызовы.

Эти вызовы бывают блокирующие и неблокирующие.

Не блокирующее чтение сообщит, что данных пока нет. Блокирующее дождётся.

Но эти вызовы очень дорогие по времени, т.к. в момент их вызова останавливается работа процесса.

Когда у тебя десятки, сотни или тысячи «сокетов», вызывать для каждого не блокирующее чтение накладно. Для это ввели разные XXXpoll, они позволяют одним системным запросом узнать статус множества «сокетов». Что заметно быстрее.

Асинхронные вычисления это другой мир. У нас есть тысячи мелких задач. Но каждая асинхронная задача - это объект. Когда завезли async/await в Rust, с ними пришли Future и прочее. А компилятор научился создавать такие объекты. А каждый await компилятор заменяет на выход из задачи.

tokio - это один из движков, он предоставляет и «каналы» для общения между задачами, и управляет задачами. так же он предлагает обвязки над «сокетами» (например, tokio::io::stdin()). Такие движки сами управляют «сокетами» через блокирующие/неблокирующие вызовы и XXXpoll. А «задачам» даёт свои «каналы» для работы с «сокетами».

Хочешь глубже понять, решай задачи. Например:

В программе два потока. Один считывает блокирующей функцией stdin и передаёт их в «канал» (который надо реализовать самому). Второй поток считывает данные из «канала», обрабатывает их, а результат выводит в stdout.

AlexVR ★★★★★
()

Я кажеться нашёл инфу которую надо.

Там даже картинки есть как это ring buffer устроен, как я такое люблю

Так вот, моя ошибка была в поиске не использовать слова implementation details, вот что мне по настоящему надо было. Ну и моя цель была понимать какие приколы можно творить с pipe-ами, а особенно в случаях, когда код изменить можно только в родительском или дочернем процессе. Просто например такая вешь как splice очень непонятно, потому что ссылаеться на имплементацию, а когда увидел имплементацию то понимаешь, что splice чуть-чуть помогает не копировать данные, да ценной сложности кода, но мне все варианты нужны

Trame
() автор топика