K>>А вот я считаю, что многопоточность не нужна. По крайней мере не нужна в том виде, в каком она сделана сейчас почти везде. Нельзя свободно давать писать разным потокам в одну облась памяти, а затем долго трахаться с выявлением всех дед локов и рэйс кондишенов, и в итоге получить решение, работающее в разы медленнее чем однопоточное. S>Ну а что вместо потоков?
Ну я ж говорю, процессы или ассинхронность. Ну если потоки, то они не должны по умолчанию иметь свободный доступ к одной области памяти (так к ак это всегда приводит к ошибкам), это может решаться на уровне компилятора. Те потоки, которые есть сейчас, практически всегда приводят к ошибкам или тормозам на ровном месте. Даже очень опытные разработчики эти ошибки делают.
S>Ну можно например держать поток(и) только для записи и организовать очередь. Можно сделать версионность как в БД для чтения.
Для этой цели можно использовать процесс, и shared memory, ну или какое-либо другое средство межпроцесного взаимодействия. А с потоками, кто-то потом обязательно захочит своими кривыми руками приделать, например мониторинг размера очереди, а потом, еще непосредственно перед записью вызвать какой-нибудь коллбек, чтоб сообщить чтовсе записалось. В итоге получить где-нибудь race condition
K>>Для параллельного исполнения вполне можно и нужно использовать несколько процессов а не потоков. Для того, чтоб организовать работу нескольких задач в рамках одного процесса можно и нужно использовать ассинхронность. А от тредов одни проблемы! Впринципе так оно и работало когда-то, не знаю, почему в свое время начали активно везде внедрять эти потоки, причем их активно пропагандировали еще до массового появления многоядерных процессоров.
S> Ну вот берем БД и как несколько процессов решит проблему проблему с чтением записью в файл.
не совсем понимаю, в чем проблема? почему это нельзя организовать с процессами или ассинхронностью? Возможно я не понял задачу, опиши подробнее?
Здравствуйте, ksandro, Вы писали:
K>Ну, расскажи! Какие вообще плюсы у потоков перед процессами?
В гугле забанили?
В чем же, в таком случае, заключается преимущество многопоточности Linux перед многопроцессностью? В многопоточных приложениях Linux для создания дополнительных потоков используются процессы особого типа. Эти процессы представляют собой обычные дочерние процессы главного процесса, но они разделяют с главным процессом адресное пространство, файловые дескрипторы и обработчики сигналов. Для обозначения процессов этого типа, применяется специальный термин – легкие процессы (lightweight processes). Прилагательное «легкий» в названии процессов- потоков вполне оправдано. Поскольку этим процессам не нужно создавать собственную копию адресного пространства (и других ресурсов) своего процесса- родителя, создание нового легкого процесса требует значительно меньших затрат, чем создание полновесного дочернего процесса.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, ksandro, Вы писали:
K>>Ну, расскажи! Какие вообще плюсы у потоков перед процессами?
НС>В гугле забанили? НС>
НС> В чем же, в таком случае, заключается преимущество многопоточности Linux перед многопроцессностью? В многопоточных приложениях Linux для создания дополнительных потоков используются процессы особого типа. Эти процессы представляют собой обычные дочерние процессы главного процесса, но они разделяют с главным процессом адресное пространство, файловые дескрипторы и обработчики сигналов. Для обозначения процессов этого типа, применяется специальный термин – легкие процессы (lightweight processes). Прилагательное «легкий» в названии процессов- потоков вполне оправдано. Поскольку этим процессам не нужно создавать собственную копию адресного пространства (и других ресурсов) своего процесса- родителя, создание нового легкого процесса требует значительно меньших затрат, чем создание полновесного дочернего процесса.
Судя по этой цитате, единственный плюс заключается в том, что поток создать быстрее чем процесс. Но понимаешь, такое дело, что создать новый поток все равно не так уж и быстро, и постоянно плодить и убивать множество новых потоков все равно довольно накладно и неэффективно. Поэтому на практике как правило используют пул потоков. То есть создают на старте некоторое оптимальное для данной системы количество потоков, и затем, раскидывают между ними задачи через очередь. Премиущества пула потоков перед пулом процессов я не вижу. Есть конечно программы которые постоянно порождают и убивают новые треды, но это плохой стиль, тормозит и работает медлено.
Так что ИМХО плюсы от более быстрого создания потока по сравнению с процессом, никак не могут превесить огромное количество трудноотлавливаемых ошибок, которое мы получаем из за общего адресного пространства.
Здравствуйте, ksandro, Вы писали:
S>> Ну вот берем БД и как несколько процессов решит проблему проблему с чтением записью в файл. K>не совсем понимаю, в чем проблема? почему это нельзя организовать с процессами или ассинхронностью? Возможно я не понял задачу, опиши подробнее?
Понятие асинхронность растяжимое. Асинхронность может жить и на одном потоке.
У тебя доступ к файлу будет из разных процессов. Это ничем не отличается от доступа к файлу из разных потоков.
Буду те же проблемы с записью и блокировками на запись и чтение. Версионность помогает в чтении, но все равно будут блокировки на время записи из разных процессов записывающих одинаковый набор записей.
В БД могут быть блокировки на уровне записи или страницы. Никуда ты от блокировок не уйдешь. Хоть и shared memory хоть mapped file. В .Net еще есть и домены
Процесс то выполняется тоже в потоке. Будет столько же потоков сколько и процессов
и солнце б утром не вставало, когда бы не было меня
K>Судя по этой цитате, единственный плюс заключается в том, что поток создать быстрее чем процесс. Но понимаешь, такое дело, что создать новый поток все равно не так уж и быстро, и постоянно плодить и убивать множество новых потоков все равно довольно накладно и неэффективно. Поэтому на практике как правило используют пул потоков. То есть создают на старте некоторое оптимальное для данной системы количество потоков, и затем, раскидывают между ними задачи через очередь. Премиущества пула потоков перед пулом процессов я не вижу. Есть конечно программы которые постоянно порождают и убивают новые треды, но это плохой стиль, тормозит и работает медлено.
K>Так что ИМХО плюсы от более быстрого создания потока по сравнению с процессом, никак не могут превесить огромное количество трудноотлавливаемых ошибок, которое мы получаем из за общего адресного пространства.
Вообще то используются пулы потоков, на коих и работает асинхронность и TPL
и солнце б утром не вставало, когда бы не было меня
S>>2) В дотнете есть такая штука как TPL. Вот это уже та самая асинхронность.
S>>TPL для асинхронности не нужна. НС>В цитате нет слов "обязательно" и "нужна".
Это не та самая асинхронность.
НС>>>Потому что continuation может быть без тасков и таски без continuation. S>>continuation это таска-продолжение другой таски, как она может быть без? НС>Может быть ровно одна таска. Может быть Parallel.For. И т.п.
Одна значит одна, ей продолжения не нужны. Parallel.For к чему? Это вообще блокирующий вызов.
S>> Хотелось бы пример: S>>
S>>continuation может быть без тасков
НС>yield
Путаете продолжение -- структура данных, которая может быть запланирована -- с ко-рутинами.
S>>>2) В дотнете есть такая штука как TPL. Вот это уже та самая асинхронность.
S>>>TPL для асинхронности не нужна. НС>>В цитате нет слов "обязательно" и "нужна". S>Это не та самая асинхронность.
Почему не та самая? Это какая то другая асинхронность?
S>>>continuation это таска-продолжение другой таски, как она может быть без? НС>>Может быть ровно одна таска. Может быть Parallel.For. И т.п. S>Одна значит одна, ей продолжения не нужны.
Ну то есть таски это таки не продолжения?
S> Parallel.For к чему?
К тому что это, внезапно, часть TPL и там внутри таки таски, довольно интересно устроенные.
S>>> Хотелось бы пример: S>>>
S>>>continuation может быть без тасков
НС>>yield S>Путаете продолжение -- структура данных,
Я ничего не путаю, я просто пытаюсь объяснить понятным тебе языком. Структура данных там IEnumerable. Но без вставок императивного кода это не продолжение.
Здравствуйте, Serginio1, Вы писали:
S>>> Ну вот берем БД и как несколько процессов решит проблему проблему с чтением записью в файл. K>>не совсем понимаю, в чем проблема? почему это нельзя организовать с процессами или ассинхронностью? Возможно я не понял задачу, опиши подробнее? S> Понятие асинхронность растяжимое.
Ничего растяжимого там нет. Оно не растяжимое, оно абстрактное.
Здравствуйте, ksandro, Вы писали:
K>Судя по этой цитате, единственный плюс заключается в том, что поток создать быстрее чем процесс.
Да. И меньше накладных расходов на создание. И меньше затрат на межпроцессное взаимодействие, так как адресное пространство общее.
K>Так что ИМХО плюсы от более быстрого создания потока по сравнению с процессом,
Поскольку из линуха потоки так и не выпилили, хотя там разница по ресурсам между процессом и потоком минимальна из всех популярных ОС, то практика нам как бы говорит что плюсы есть и существенные.
K>никак не могут превесить огромное количество трудноотлавливаемых ошибок, которое мы получаем из за общего адресного пространства.
Подавляющее большинство ошибок порождается чисто логическими проблемами — гонками и дедлоками. От того что ты разнесешь код на разные процессы эти проблемы никуда не денутся.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Почему не та самая? Это какая то другая асинхронность?
Для асинхронности TPL и параллельность не нужна.
S>>>>continuation это таска-продолжение другой таски, как она может быть без? НС>>>Может быть ровно одна таска. Может быть Parallel.For. И т.п. S>>Одна значит одна, ей продолжения не нужны. НС>Ну то есть таски это таки не продолжения?
Как можно было сделать такой вывод из примера, где по бизнес логике нам нужна одна таска -- я
S>> Parallel.For к чему? НС>К тому что это, внезапно, часть TPL и там внутри таки таски, довольно интересно устроенные.
И?
S>>Путаете продолжение -- структура данных, НС>Я ничего не путаю, я просто пытаюсь объяснить понятным тебе языком. Структура данных там IEnumerable.
Структура данных там КА, который использует всего лишь один метод IEnumerable.
НС>Но без вставок императивного кода это не продолжение.
Не совсем понял, причем здесь вставки императивного кода, но таки yield -- это не продолжение. Yield не про многопоточность, поток там будет один.
НС>Да. И меньше накладных расходов на создание.
Да, расходов на создание меньше, но это не слишком важно, если не плодить кучу потоков, а плодить кучу потоков не самый лучший стиль.
НС>И меньше затрат на межпроцессное взаимодействие, так как адресное пространство общее.
Почему это их меньше? Любое взаимодействие в общем случае происходит через некоторую область памяти, доступ к ней надо синхронизировать. Более того, общее адресное пространство скорее увеличивает вероятность всяких неочевидных проблем, таких проблем как например false sharing. Так что расходов точно не меньше, а скорее даже больше.
НС>Поскольку из линуха потоки так и не выпилили, хотя там разница по ресурсам между процессом и потоком минимальна из всех популярных ОС, то практика нам как бы говорит что плюсы есть и существенные.
Вот интересно, что это за существенные плюсы? ИМХО не выпилили, потому, что все стали пользоваться
K>>никак не могут превесить огромное количество трудноотлавливаемых ошибок, которое мы получаем из за общего адресного пространства.
НС>Подавляющее большинство ошибок порождается чисто логическими проблемами — гонками и дедлоками. От того что ты разнесешь код на разные процессы эти проблемы никуда не денутся.
Да, это чисто логические проблемы, но на приактике любое обращение к любой переменной может в итоге вызвать race condition, в сколь-нибудь большом проекте практически невозможно определить, что к переменной нет обращения из другого потока, и даже если его действительно нет, то ты никак-не гарантируешь, что кто-нибудь не обратится к ней в будущем. В итоге, часто люди перестраховываясть начинают синхронизировать все что можно, чем вызывают дикие тормоза и дедлоки. У процессов общение происходит через вполне конкретные средства межпроцессного взаимодействия. То, есть если ты пишешь куда-нибудьв shared mamory или pipe ты сразу знаешь, что это будет использоваться другим процессом, и только это, другой процесс не залезет в тебе в какой-нибудь массив и не изгадит тебе весь стек. Процесс вполне корректно можно убить средствами ос, корректно убить зависший поток невозможно. Ну есть еще много мелких ньюансов. Я не против потоков вообще, я против того, как они сделаны, любое обращение к любой переменной в многопоточной программе может вызвать фатальную ошибку и испортить все данные, что может быть хуже?
Какого хрена "синхронное плаванье" — это когда тётки одновременно в воде кувыркаются, а синхронное программирование — это когда процессы по очереди выполняются? Диаметрально противоположный смысл.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, ksandro, Вы писали:
K>>Судя по этой цитате, единственный плюс заключается в том, что поток создать быстрее чем процесс. Но понимаешь, такое дело, что создать новый поток все равно не так уж и быстро, и постоянно плодить и убивать множество новых потоков все равно довольно накладно и неэффективно. Поэтому на практике как правило используют пул потоков. То есть создают на старте некоторое оптимальное для данной системы количество потоков, и затем, раскидывают между ними задачи через очередь. Премиущества пула потоков перед пулом процессов я не вижу. Есть конечно программы которые постоянно порождают и убивают новые треды, но это плохой стиль, тормозит и работает медлено.
K>>Так что ИМХО плюсы от более быстрого создания потока по сравнению с процессом, никак не могут превесить огромное количество трудноотлавливаемых ошибок, которое мы получаем из за общего адресного пространства.
S> Вообще то используются пулы потоков, на коих и работает асинхронность и TPL
Ну, вот я говорю, что для большинства задач пулы потоков вполне можно заменить на пулы процессов.
А ассинхронность внутри процесса вполне можно реализовывать с помощью кооперативной многозадачности, что вроде и должны помогать сделать все эти "новомодные" async await (хотя концепция корутин очень старая).
ссылка битая
S>>Или имеется в виду запуск callback'а в самом ядре, а там разве нет потоков, стеков? _>Да, в ядре нет потоков. Но я подразумевал естественно не запуск колбеков в ядре, потому как ядро исполняется с привилегиями нулевого кольца, которые нельзя давать коду пользовательских приложений. Я имел ввиду что ядро могло бы напрямую инициировать запуск пользовательского кода, но естественно только внутри пользовательского процесса, в 3-ем кольце защиты.
Ну так и происходит, ядро дергает код в пользовательском процессе,не напрямую, а через соотв. поток.
S>>По числу ядер, домноженное, наверное, на 2 (ht). _>Ну т.е. при таком подходе у тебя априори в разы больше висящих в блокировке потоков, чем при честном сихнронном вводе-выводе в отдельном потоке. ))) И да, на самом деле в этих висящих потоках конечно же ничего страшного нет. Просто не надо мифологизировать, что их нет, как вот в той бредовой статье.
Ну висят они, как я понимаю на completionport, ждут как-нибудь данных. Это же не блокировка по соотв. io, а ожиданию любых io.
Здравствуйте, Ночной Смотрящий, Вы писали:
_>>Ничего себе. И что, все они стартуют сразу при старте любого .net приложения? Или надо начать асинхронный ввод-вывод? Или всё же не все сразу? НС>Странные вопросы. Зачем им стартовать сразу?
Почему странные? Я просто не в курсе как оно там в .net реализовано, вот и спрашиваю. Обычно при организации пулов потоков они все сразу стартуют. Правда при этом их число чаще всего равно числу логических ядер процессора.
Здравствуйте, Sharov, Вы писали:
_>>Я тут имел в виду, что если ты напишешь что-то вроде: _>>
_>>data=await DownloadFile();
_>>Parse(data);
_>>
_>>в gui потоке, то функция parse опять же будет вызвана в gui потоке, который на момент отработки соответствующего Iocp потока вполне может быть чем-то занят. S>Отличный пример! Не будет он ничего ждать, потому что именно для этого существует контекст S>синхронизации(synchronizationcontext). iocp поток сделает post соотв. контексту и будет свободен. S>За одно еще больше понял роль всяческих synchronizationcontext'ов.
IOCP поток естественно не будет ничего ждать. А вот "обработка данных, пришедших по сети" будет произведена только после ожиданий (причём в такой модели двойных).
Понимаешь, на самом деле все эти ждущие потоки (что в синхронном варианте, что в асинхронном) — это абсолютно не страшная вещь. И я акцентировал внимание на их наличие в асинхронном коде только по той причине, что некоторые дурачки утверждали в своих статьях, что их нет и что как раз по этому асинхронный код намного лучше. Нет, они как раз есть. Но в этом ничего страшного с точки зрения эффективности нет. А вот что реально "страшно" с точки зрения эффективности работы программы, так это суммарная задержка от момента попадания пакета в сетевую карту, до момента его обработки в прикладном коде. Потому как рассуждать о количестве выдерживаемых в минуту запросов без уточнения величины латентности могут только очень сомнительные специалисты.
Здравствуйте, ksandro, Вы писали:
K>А вот я считаю, что многопоточность не нужна. По крайней мере не нужна в том виде, в каком она сделана сейчас почти везде. Нельзя свободно давать писать разным потокам в одну облась памяти, а затем долго трахаться с выявлением всех дед локов и рэйс кондишенов, и в итоге получить решение, работающее в разы медленнее чем однопоточное.
Это ты тут свой опыт пересказываешь? ) Ну возможно стоило в начале ознакомиться с теорией вопроса (общепринятыми практиками решения этих проблем), а потом уже собственно кодить? )
K>Для параллельного исполнения вполне можно и нужно использовать несколько процессов а не потоков. Для того, чтоб организовать работу нескольких задач в рамках одного процесса можно и нужно использовать ассинхронность. А от тредов одни проблемы! Впринципе так оно и работало когда-то, не знаю, почему в свое время начали активно везде внедрять эти потоки, причем их активно пропагандировали еще до массового появления многоядерных процессоров.
У процессов по сравнению с потоками есть только недостатки и ни единого достоинства. Если в задаче требуется использование общей памяти разными задачами, то тебе в любом случае понадобятся какие-то примитивы синхронизации. Что между процессами, что между потоками. И единственная разница будет в том, что в случае процессов тебе придётся написать ещё кучи глупого кода по организации общей памяти.
Здравствуйте, ksandro, Вы писали:
K>Да, это чисто логические проблемы, но на приактике любое обращение к любой переменной может в итоге вызвать race condition, в сколь-нибудь большом проекте практически невозможно определить, что к переменной нет обращения из другого потока, и даже если его действительно нет, то ты никак-не гарантируешь, что кто-нибудь не обратится к ней в будущем.
Ну вот например при программирование на языке Rust, компилятор гарантирует тебе отсутствие таких проблем.
K>В итоге, часто люди перестраховываясть начинают синхронизировать все что можно, чем вызывают дикие тормоза и дедлоки.
А таких "специалистов" лучше вообще не допускать до программирования.
K>У процессов общение происходит через вполне конкретные средства межпроцессного взаимодействия. То, есть если ты пишешь куда-нибудьв shared mamory или pipe ты сразу знаешь, что это будет использоваться другим процессом, и только это, другой процесс не залезет в тебе в какой-нибудь массив и не изгадит тебе весь стек. Процесс вполне корректно можно убить средствами ос, корректно убить зависший поток невозможно. Ну есть еще много мелких ньюансов. Я не против потоков вообще, я против того, как они сделаны, любое обращение к любой переменной в многопоточной программе может вызвать фатальную ошибку и испортить все данные, что может быть хуже?
Т.е. я правильно понимаю, что ты предлагаешь использовать необходимость написания ненужного кода по организации междпроцессного взаимодействия в качестве инструмента исправляющего неумение некоторых программистов организовывать свой код? )))
Здравствуйте, Sharov, Вы писали:
S>>>Как что-то (т.е. какой-либо код) в пространстве процесса может быть запущено без потока и стека? _>>Я же специально написал, где можно посмотреть пример подобного. https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D0%B3%D0%BD%D0%B0%D0%BB_(Unix) S>ссылка битая
Ох, ну мог бы и сам заметить, что движок форума просто не подставил в саму ссылку последнюю закрывающую скобку, скопировал бы весь текст ссылки и всё. Ну если это так сложно, то вот: НЕ БИТАЯ ССЫЛКА.
S>>>Или имеется в виду запуск callback'а в самом ядре, а там разве нет потоков, стеков? _>>Да, в ядре нет потоков. Но я подразумевал естественно не запуск колбеков в ядре, потому как ядро исполняется с привилегиями нулевого кольца, которые нельзя давать коду пользовательских приложений. Я имел ввиду что ядро могло бы напрямую инициировать запуск пользовательского кода, но естественно только внутри пользовательского процесса, в 3-ем кольце защиты. S>Ну так и происходит, ядро дергает код в пользовательском процессе,не напрямую, а через соотв. поток.
Ядро тут ничего не дёргает, а просто выставляет флаг (ну или в случае винды помещает сообщение в очередь). А поток в пользовательском процессе реагирует на это уж точно не сразу, а когда-то там в отдалённом будущем, через неопределённое время (которое в теории и часами может быть).
S>>>По числу ядер, домноженное, наверное, на 2 (ht). _>>Ну т.е. при таком подходе у тебя априори в разы больше висящих в блокировке потоков, чем при честном сихнронном вводе-выводе в отдельном потоке. ))) И да, на самом деле в этих висящих потоках конечно же ничего страшного нет. Просто не надо мифологизировать, что их нет, как вот в той бредовой статье. S>Ну висят они, как я понимаю на completionport, ждут как-нибудь данных. Это же не блокировка по соотв. io, а ожиданию любых io.
Так я и нигде не говорил, что это что-то плохое. Просто не надо писать глупости, что их нет и поэтому асинхронный ввод-вывод лучше. Всё абсолютно одинаково (разве что в асинхронном варианте есть ещё небольшая порция "лишнего" код на обслуживание очередей).
Здравствуйте, alex_public, Вы писали:
_>Обычно при организации пулов потоков они все сразу стартуют.
Это довольно необычно. Обычно пулы набираются по мере потребностей, пока не достигают максимального значения.
_> Правда при этом их число чаще всего равно числу логических ядер процессора.
И это тоже обычно не так. Максимальное число кратно числу ядер, но не равно ему. В дотнете сейчас довольно сложный алгоритм, раньше, в зависимости от хоста, размер пула воркер потоков был количество ядер умножить на 25 или 40, в зависимости от хоста. И это число можно было так же указать в настройках. Сейчас все сложнее, размер пула вычисляется динамически, пытаясь адаптироваться под характер нагрузки, и может как увеличиваться, так и уменьшаться в процессе.
В документации максимальные размеры пулов и алгоритмы их вычисления не указаны, т.е. они могут меняться.