Легкие темы в операционных системах
Говорят, что одним из основных преимуществ Node (и предполагаемых витых и др.) По сравнению с более традиционными многопоточными серверами является очень высокая степень параллелизма, обеспечиваемая моделью цикла событий. Основная причина этого заключается в том, что каждый поток занимает много места в памяти, а контексты обмена сравнительно дороги. Когда у вас есть тысячи потоков, сервер тратит большую часть своего времени, переключаясь с потока на поток.
Мой вопрос: почему операционные системы или базовое оборудование не поддерживают гораздо более легкие потоки? Если бы они сделали, вы могли бы решить проблему 10k с простыми потоками? Если они не могут, то почему?
2 ответа
Современные операционные системы могут поддерживать выполнение очень большого количества потоков.
В более общем смысле, аппаратное обеспечение продолжает работать быстрее (и в последнее время оно стало работать более быстрым способом, который намного удобнее для многопоточности и многопроцессорной обработки, чем для однопоточных циклов событий, т. Е. Увеличил количество ядер, а не увеличил пропускную способность обработки в одноядерный). Если вы не можете позволить себе накладные расходы сегодня, вы, вероятно, можете позволить себе это завтра.
То, что кооперативные многозадачные системы Twisted (и, по-видимому, Node.js и др.) Предлагает поверх упреждающей многопоточности (по крайней мере, в форме pthreads), - это простота программирования.
Правильное использование многопоточности подразумевает гораздо большую осторожность, чем правильное использование одного потока. Цикл обработки событий - это всего лишь средство выполнения нескольких задач, не выходя за пределы единственного потока.
Учитывая распространение параллельного оборудования, было бы идеально, если бы многопоточность или многопроцессорность стали проще (и проще - правильно). Актеры, передача сообщений, возможно, даже сети Петри - вот некоторые из решений, которые люди пытались решить эту проблему. Они по-прежнему очень маргинальны по сравнению с основным подходом многопоточности (pthreads). Другой подход - SEDA, который использует несколько потоков для запуска нескольких циклов событий. Это также не завоевало популярность.
Таким образом, люди, использующие циклы событий, вероятно, решили, что время программиста стоит больше, чем процессорное время, и люди, использующие pthreads, вероятно, решили обратное, и люди, изучающие актеров и тому подобное, хотели бы ценить оба вида времени более высоко (четко безумно, наверное, поэтому их никто не слушает).
На самом деле проблема не в том, насколько тяжелыми являются потоки, а в том, что для написания правильного многопоточного кода вам нужны блокировки на общих элементах, и это не позволяет масштабировать его с количеством потоков, потому что потоки в конечном итоге ждут друг друга, чтобы получить блокировки, и вы быстро достигните точки, в которой добавление дополнительных потоков не будет иметь эффекта или даже замедлит работу системы, поскольку вы получаете больше конфликтов блокировки.
Во многих случаях вы можете избежать блокировки, но это очень трудно сделать правильно, а иногда вам просто нужна блокировка.
Так что, если вы ограничены небольшим количеством потоков, вы можете обнаружить, что устранение накладных расходов, связанных с блокировкой ресурсов или даже размышлениями об этом, делает однопоточную программу быстрее, чем многопоточная, независимо от того, сколько потоков вы добавлять.
В основном блокировки могут (в зависимости от вашей программы) быть очень дорогими и могут остановить масштабирование вашей программы за несколько потоков. И вам почти всегда нужно что-то блокировать.
Проблема не в потоке, а в синхронизации между потоками. Даже если бы вы могли мгновенно переключаться между потоками и иметь бесконечную память, ничто из этого не помогает, если каждый поток в конечном итоге ждет своей очереди в каком-то общем ресурсе.