Здравствуйте, Константин, Вы писали:
C>>AIO никто не использует, так как для файлового IO проще использовать пулы потоков. К>Проще не значит эфективнее.
Примерно значит. Дело в том, что для AIO (что в Винде, что в Линуксе) всё равно в итоге используется поток в ядре — для создания объектов, поиска данных в кэше, обслуживания очереди и т.п. Выигрыш от AIO будет, если есть очень большая очередь IO-запросов.
Дело только в том, что по сравнению с сетью у дискового IO меньше масштабируемость. Обычно даже пара десятков параллельных writer'ов или reader'ов — это слишком много для вращающихся дисков.
C>>Под Виндой, кстати, тоже К>Нет, под виндой не тоже: в .NET это прекрасно работает.
Тоже.
C>>приколов типа блокирующегося CloseHandle К>Он блокируется только если есть pending операции. К>При правильном использовании (сначала подождать завершения pending IO потом закрывать) ничо не блокируется.
Нет такой гарантии — и на практике оно тормозит. Кстати, такой операции вообще в overlapped нет.
C>>За пределами файлового IO, epoll работает быстрее Overlapped IO из-за лучшей оптимизации TCP-стека в Линуксе. К>Подтверждения "лучшей оптимизации TCP-стека в Линуксе" есть какие-то? http://www.slideshare.net/PrincipledTechnologies/comparing-network-performance-red-hat-enterprise-linux-6-vs-microsoft-windows-server-2012 — для примера
К>>>Соответственно, асинхронный IO (и построенные на его основе технологии вроде async-await) на других платформах неизбежно будут глючить и/или тормозить. C>>Хех. Разработчики Nodejs, libev и других мультиплексирующих систем под Юниксы недоумевают. К>Разработчики этих систем не пишут на .NET.
А что, .NET магически имеет свой IO-стек?
К>Чтобы посмотреть, что получается при портировании, смотрите производитиельность Node.js на винде: они там не то что IOCP, даже overlapped IO не смогли, используют select, с ожидаемым результатом по производительности.
Не надо говорить о том, чего не знаешь. В libuv (и nodejs) используется Overlapped IO. См.: https://github.com/joyent/libuv/blob/master/src/win/core.c
К>Если бы .NET framework проектировался кросс-платформенным, об эффективном асинхронном IO можно было бы забыть, см. например состояние этого в Java.
C>>http://1-ps.googleusercontent.com/h/www.salmanq.com/wp-content/uploads/2013/03/performance-comparison-net-nodejs.png.pagespeed.ce.1YsnSc2NdF.png К>На красивом графике мы видим, что уже 200 одновременных запросах (что в условиях того теста всего лишь 67 запросов в секунду) .NET становится быстрее NodeJS.
Эээ.. Вообще-то, на графике показано, что до 200 соединений у nodejs меньше латентность. Т.е. работает она быстрее. Более 200 соединений тестов просто нет.
К>Ничего удивительного для меня в этом нет: очевидно же, что на винде, где multiplexed IO развивается ещё с 1993 года, оно будет лучше работать.
Нет, его задизайнили в 93-м и с тех пор вынуждены это пииииии поддерживать из-за невозможности сделать полноценный рефакторинг. В Линуксе оно началось с тупой реализации, которую потом несколько раз переписали до того, что она сейчас лучшая в мире.
Sapienti sat!
Re[20]: Зачем Майкрософту рубить сук, на котором он сидит?
Здравствуйте, Константин, Вы писали:
К>«обычный многопоточный IO» более-менее пригоден только для hello world, и ещё для очень узкого класса приложений, например что-то вроде офиса, когда все данные в RAM, а от IO требуется только [де]сериализация раз в полчаса на быстрый локальный диск. К>Посмотрите ради интереса, какое API использует скажем chromium для работы с диском и сетью.
Блокирующийся IO для файлового IO и epoll/kqueue/overlapped для сети. То что они сегрегируют IO и процессы-рендереры не считаем — внутри дочерних процессов используется только асинхронный API для всего.
Sapienti sat!
Re[19]: Зачем Майкрософту рубить сук, на котором он сидит?
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>В этот узкий круг, помимо серверов, входят, как минимум, смартфоны. Именно поэтому в WP искусственно покоцан весь синхронный IO из API.
С чего бы это? )
Re[21]: Зачем Майкрософту рубить сук, на котором он сидит?
Здравствуйте, alex_public, Вы писали:
НС>>В этот узкий круг, помимо серверов, входят, как минимум, смартфоны. Именно поэтому в WP искусственно покоцан весь синхронный IO из API. _>С чего бы это? )
К какой части высказывания вопрос?
Re[22]: Зачем Майкрософту рубить сук, на котором он сидит?
Здравствуйте, alex_public, Вы писали:
НС>>В этот узкий круг, помимо серверов, входят, как минимум, смартфоны. Именно поэтому в WP искусственно покоцан весь синхронный IO из API. _>С чего бы это? )
тут речь о наблюдаемой производительности (aka perceived performance).
Под wp/winrt большинство тяжёлых операций можно выполнить только асинхронно. Благодаря этому надо очень постараться, чтобы завесить UI-поток (и с определённой долей вероятности такое приложение не пройдёт в маркет). В прочих мобильных ОС ситуация прямо противоположная
Re[14]: Зачем Майкрософту рубить сук, на котором он сидит?
Здравствуйте, Константин, Вы писали:
К>В стандарте нет ничего платформозависимого. К>А вот в рантайме, есть много вещей, которые сложно перенести в силу того, что в других ОС не хватает каких-то важных кусков. К>Один из них многопоточность. К>В самом центре .NET-ового thread pool и всего асинхронного IO лежит IO completion port.
В моём случае всё, что нужно было для целевого приложения, уже было перенесено. Там даже обычного poll() хватало с головой для работы, потому что не было "10k" параллельных клиентов с отдельными соединениями на каждого, а был один большой сокет на всё. Плюс несколько небольших пулов ниток для медленных партнёров типа БД.
К>Это объект ядра, уникальный для винды (в *nix какие-то потуги, а именно kqueue и epoll, появились на много лет позже, и намного хуже работают),
Последнее утверждение требует обоснования, как минимум про kqueue.
К> и хорошо интегрированный в остальные API (в linux почему-то epoll только для сокетов, а для файлов не особо совместимый native AIO).
И в Linux, и во FreeBSD тот же AIO работает неплохо. Правда, в случае Linux нет адекватной связи между AIO и epoll (или я её не знаю). Для FreeBSD EVFILT_AIO подключает статус завершения операции.
К>Соответственно, асинхронный IO (и построенные на его основе технологии вроде async-await) на других платформах неизбежно будут глючить и/или тормозить.
Я не увидел достаточно обоснований для такого вывода.
К>Второй из них 3D графика.
Как уже сказал, мне она тут совершенно пофиг, у меня другие задачи.
К>Соответственно, «подумать не только про виндовую среду» означало бы, что .NET лишился бы существенных преимуществ, и стал бы ещё одной Java, которая конечно переносима ОК, только ни на одной платформе нормально не работает
"Нормально" для каких целей? Сеть — штука на 99% кроссплатформенная.
The God is real, unless declared integer.
Re[15]: Зачем Майкрософту рубить сук, на котором он сидит?
Здравствуйте, netch80, Вы писали:
К>> и хорошо интегрированный в остальные API (в linux почему-то epoll только для сокетов, а для файлов не особо совместимый native AIO). N>И в Linux, и во FreeBSD тот же AIO работает неплохо. Правда, в случае Linux нет адекватной связи между AIO и epoll (или я её не знаю).
Есть несколько вариантов:
1) Использовать сигналы для нотификаций — напрямую или через signalfd().
2) eventfd() для превращения event'ов в дескрипторы для epoll()
Sapienti sat!
Re[20]: Зачем Майкрософту рубить сук, на котором он сидит?
Здравствуйте, Константин, Вы писали:
_>>Я подразумевал совсем не то, что вне нагруженных серверов наплевать на ресурсы. _>>Я намекаю, что асинхронный IO будет эффективнее обычного многопоточного только на очень узком круге задач. К>Это ошибка так считать. К>Как только число одновременно работающих файлов/сокетов сравняется с числом ядер, асинхронный IO станет эффективнее.
С этим вполне можно согласиться (хотя детали организации могут портить картину).
К>Если в системе есть и другие активные процессы, "эффективнее" станет "в разы эффективнее". К>А если число файлов на пару порядков превысит число ядер, у вас тупо кончится память, потому что потоки очень дорогой системный ресурс.
Серьёзно, винда на среднем десктопе от 400 ниток уже выжирает память? Что-то мне даже про неё не верится. Linux спокойно выдержит тысяч 30 при дефолтных настройках и миллионы при разумном тюнинге. Кажется, Вы что-то таки спутали.
Или речь про адресное пространство в 32 битах? Тогда не надо говорить про "дорогой системный ресурс", это не системный ресурс, а ресурс процесса.
Если принять за основу, что нить в Windows очень дорога в держании и переключении, то неудивительно стремление MS к IOCP — выигрыш идёт действительно в разы. В Linux разница значительно меньше.
К>«обычный многопоточный IO» более-менее пригоден только для hello world, и ещё для очень узкого класса приложений, например что-то вроде офиса, когда все данные в RAM, а от IO требуется только [де]сериализация раз в полчаса на быстрый локальный диск. К>Посмотрите ради интереса, какое API использует скажем chromium для работы с диском и сетью.
Это показывает пока что только то, что его изначально рассчитывали в том числе и на системы, где нить является крайне дорогой сущностью (как по Вашему описанию в Windows).
API в стиле "заказать операцию, ждать callback", кроме того, универсально тем, что оно достаточно легко превращается с помощью врапперов в API с ожиданием результата, если требуется таки синхронная реализация (в первый раз такую технологию использовали, кажется, ещё в OS/360). Но это значит всего лишь, что выставлены в userland ядерные потроха (с минимальной защитой).
К>Например, по этой причине из нового WinAPI повыкидывали вызовы, которые могут блокировать вызывающий поток хотя бы на 50 миллисекунд.
Здравствуйте, Cyberax, Вы писали:
К>>> и хорошо интегрированный в остальные API (в linux почему-то epoll только для сокетов, а для файлов не особо совместимый native AIO). N>>И в Linux, и во FreeBSD тот же AIO работает неплохо. Правда, в случае Linux нет адекватной связи между AIO и epoll (или я её не знаю). C>Есть несколько вариантов: C>1) Использовать сигналы для нотификаций — напрямую или через signalfd().
Похоже. Но сигналов тут ограниченное количество.
C>2) eventfd() для превращения event'ов в дескрипторы для epoll()
Примеры, которые я вижу, используют io_submit(), который фиг так просто вызовешь.
Интересно, почему не lio_listio().
The God is real, unless declared integer.
Re[21]: Зачем Майкрософту рубить сук, на котором он сидит?
Здравствуйте, netch80, Вы писали:
N>Серьёзно, винда на среднем десктопе от 400 ниток уже выжирает память? Что-то мне даже про неё не верится. Linux спокойно выдержит тысяч 30 при дефолтных настройках и миллионы при разумном тюнинге. Кажется, Вы что-то таки спутали. N>Если принять за основу, что нить в Windows очень дорога в держании и переключении, то неудивительно стремление MS к IOCP — выигрыш идёт действительно в разы. В Linux разница значительно меньше.
Дело не столько в "дорога в держании и переключении", сколько в накладных расходах на kernel switch и загруженный впустую планировщик. Сравни сам:
static void Main(string[] args)
{
//RunTasks().Wait();
RunThreads();
}
static int s_TaskCount;
static async Task RunTasks()
{
int i = 0;
while (true)
{
i++;
Task.Run(async () =>
{
Interlocked.Increment(ref s_TaskCount);
await Task.Delay(5000).ConfigureAwait(false);
Interlocked.Decrement(ref s_TaskCount);
});
i++;
if (i % 100 == 0)
{
await Task.Yield();
Console.WriteLine(s_TaskCount.ToString("N"));
}
}
}
static int s_ThreadsCount;
static void RunThreads()
{
int i = 0;
while (true)
{
new Thread(() =>
{
Interlocked.Increment(ref s_ThreadsCount);
Thread.Sleep(5000);
Interlocked.Decrement(ref s_ThreadsCount);
},
100 * 1024).Start();
i++;
if (i % 100 == 0)
{
Console.WriteLine(s_ThreadsCount.ToString("N"));
Thread.Yield();
}
}
}
Вариант с потоками под x86 затыкается с OutOfMemory уже на ~3000 потоков (несмотря на стек в 100 кб), под x64 — стабилизируется где-то на 30k потоков.
Вариант с тасками спокойно пережёвывает 800k одновременно работающих тасков.
Если перейти на пул потоков с IOCP при должном везении получается нечто среднее.
N>И в результате 99% индусов будут писать в духе
Здравствуйте, netch80, Вы писали:
C>>Есть несколько вариантов: C>>1) Использовать сигналы для нотификаций — напрямую или через signalfd(). N>Похоже. Но сигналов тут ограниченное количество.
Для простой нотификации сойдёт — просто прервать epoll и дальше посмотреть что там пришло.
C>>2) eventfd() для превращения event'ов в дескрипторы для epoll() N>Примеры, которые я вижу, используют io_submit(), который фиг так просто вызовешь. N>Интересно, почему не lio_listio().
Должно работать и с ним.
Sapienti sat!
Re[22]: Зачем Майкрософту рубить сук, на котором он сидит?
Здравствуйте, Sinix, Вы писали:
S>Под wp/winrt большинство тяжёлых операций можно выполнить только асинхронно. Благодаря этому надо очень постараться, чтобы завесить UI-поток (и с определённой долей вероятности такое приложение не пройдёт в маркет). В прочих мобильных ОС ситуация прямо противоположная
Ну так а зачем запускать тяжёлые операции в UI потоке, а не в отдельном? )
Re[23]: Зачем Майкрософту рубить сук, на котором он сидит?
Здравствуйте, alex_public, Вы писали:
_>Ну так а зачем запускать тяжёлые операции в UI потоке, а не в отдельном? )
В терминах мобильных приложений к "тяжёлым" относится всё, что может завесить поток больше, чем на 50 миллисекунд. Т.е. любой ввод-вывод как минимум.
Жёстко конечно, зато я не видел ни одного намертво зависшего приложения под wp/winrt, в отличие от всех прочих платформ.
Re[22]: Зачем Майкрософту рубить сук, на котором он сидит?
Здравствуйте, Sinix, Вы писали:
S>Дело не столько в "дорога в держании и переключении", сколько в накладных расходах на kernel switch и загруженный впустую планировщик. Сравни сам: S>... S>Вариант с потоками под x86 затыкается с OutOfMemory уже на ~3000 потоков (несмотря на стек в 100 кб), под x64 — стабилизируется где-то на 30k потоков.
Это исключительно проблемы .net'a. ) Аналогичный код на C++ спокойно стабилизируется где-то на 11 000 потоков на древнейшей машине (WinXP 32 бита, Core2Duo, 2Гб). Т.е. на современном процессоре было бы под 50К (на тех же 32 битах).
S>Вариант с тасками спокойно пережёвывает 800k одновременно работающих тасков.
Естественно. Потому как этот тест измеряет совсем другое. Тут скорее соревнование в накладных расходах на создание потока/задачи. И т.к. здесь время работы (а не жизни) потока микроскопическое в сравнение с процессом создания потока (а у внутренних задачек тут всё хорошо), то такой вариант естественно получается невыгодным. А вот если эти же 5 секунд поток/задача будут заняты вычислениями, то у нас будет совсем другой расклад...
Но вообще, я конечно же согласен, что в случае многих тысяч одновременных задач правильнее переходит от системной многозадачности, к внутренней рукопашной (и как следствие этого, асинхронный IO). Только это же у нас опять же получается крайне узкая область применения, о чём я и говорил изначально.
Re[24]: Зачем Майкрософту рубить сук, на котором он сидит?
Здравствуйте, Sinix, Вы писали:
_>>Ну так а зачем запускать тяжёлые операции в UI потоке, а не в отдельном? ) S>В терминах мобильных приложений к "тяжёлым" относится всё, что может завесить поток больше, чем на 50 миллисекунд. Т.е. любой ввод-вывод как минимум.
И как это отвечает на мой вопрос? )
S>Жёстко конечно, зато я не видел ни одного намертво зависшего приложения под wp/winrt, в отличие от всех прочих платформ.
Похоже что данного преимущества недостаточно для популярности платформы. Кстати, сама винда это показывала в далёком прошлом: более открытая платформа выигрывает, даже если она более глючная.
Re[23]: Зачем Майкрософту рубить сук, на котором он сидит?
Здравствуйте, alex_public, Вы писали:
_>Это исключительно проблемы .net'a. ) Аналогичный код на C++ спокойно стабилизируется где-то на 11 000 потоков на древнейшей машине (WinXP 32 бита, Core2Duo, 2Гб). Т.е. на современном процессоре было бы под 50К (на тех же 32 битах).
Вот тут я не уверен честно говоря От .net-а там всего ничего, почти всё уходит в нативные вызовы. Как вариант — выложите бинарник, проверю.
Кстати, а в запускаюшем коде есть что-то типа Thread.Yield? Без него "рабочие" потоки скорее ждут своей очереди на завершение чем работают. С тасками так счётчик растёт до нескольких миллионов, что конечно же неверно.
S>>А вот если эти же 5 секунд поток/задача будут заняты вычислениями, то у нас будет совсем другой расклад...
Ну да. Тогда максимально эффективным будет подход "поток на ядро" (плюс-минус). Таски/пулы потоков в принципе именно этим и занимаются, просто делают балансировку незаметной для пользователя
_>Но вообще, я конечно же согласен, что в случае многих тысяч одновременных задач правильнее переходит от системной многозадачности, к внутренней рукопашной (и как следствие этого, асинхронный IO). Только это же у нас опять же получается крайне узкая область применения, о чём я и говорил изначально.
Это во многом зависит от дизайна языка и фреймворка. Для дотнета замена абсолютно прозрачна. Для скалы/эрланга — незаметна в принципе.
Re[22]: Зачем Майкрософту рубить сук, на котором он сидит?
Здравствуйте, Sinix, Вы писали:
S>Вот тут я не уверен честно говоря От .net-а там всего ничего, почти всё уходит в нативные вызовы. Как вариант — выложите бинарник, проверю.
Легко: http://files.rsdn.ru/98162/test.exe
S>Кстати, а в запускаюшем коде есть что-то типа Thread.Yield? Без него "рабочие" потоки скорее ждут своей очереди на завершение чем работают. С тасками так счётчик растёт до нескольких миллионов, что конечно же неверно.
Thread.Yield это в реальности функция SwitchToThread из win api. И её добавление/убирание для потоков в данном случае естественно никак не влияет на ситуацию — не стоит путать кооперативную и вытесняющую многозадачность.
S>Это во многом зависит от дизайна языка и фреймворка. Для дотнета замена абсолютно прозрачна. Для скалы/эрланга — незаметна в принципе.
Ну начнём с того, что для обычного десктопного ПО (с 1-10 одновременными задачами) асинхронная работа ещё и менее эффективна, чем синхронная. Правда для такого ПО опять же обычно глубоко наплевать на такие нюансы эффективности.
Но главный вопрос в другом: а зачем менять код с системных потоков на лёгкие для обычного ПО? Т.е. как у нас это соотносится с принципом Оккама? )