Я боюсь, что я "делаю не то" здесь, если так, удалите меня, и я извиняюсь. В частности, я не вижу, как я создаю аккуратные маленькие аннотации, которые создали некоторые люди. Тем не менее, у меня есть много проблем / замечаний, чтобы сделать в этой теме.
1) Закомментированный элемент в псевдокоде в одном из популярных ответов
result = query( "select smurfs from some_mushroom" );
// twiddle fingers
go_do_something_with_result( result );
по сути фальшивая. Если поток вычисляет, то он не крутит большие пальцы, он выполняет необходимую работу. Если, с другой стороны, он просто ожидает завершения ввода-вывода, то он не использует процессорное время, весь смысл инфраструктуры управления потоками в ядре состоит в том, что процессор найдет что-то полезное для выполнения. Единственный способ «перевернуть свои пальцы», как предлагается здесь, - создать цикл опроса, и никто, кто закодировал реальный веб-сервер, не настолько неспособен сделать это.
2) «Потоки сложны», имеет смысл только в контексте обмена данными. Если у вас есть по существу независимые потоки, как, например, в случае обработки независимых веб-запросов, то создание потоков является тривиально простым, вы просто кодируете линейный поток обработки одной работы и сидите, зная, что она будет обрабатывать несколько запросов, и каждый будет эффективно независимым. Лично я бы рискнул, что для большинства программистов изучение механизма закрытия / обратного вызова является более сложным, чем простое кодирование версии потока сверху вниз. (Но да, если вам нужно общаться между потоками, жизнь становится действительно тяжелой и очень быстрой, но тогда я не уверен, что механизм закрытия / обратного вызова действительно меняет это, он просто ограничивает ваши варианты, потому что этот подход все еще достижим с потоками Во всяком случае, это
3) До сих пор никто не представил никаких реальных доказательств того, почему один конкретный тип переключения контекста будет более или менее трудоемким, чем любой другой тип. Мой опыт создания многозадачных ядер (в небольшом масштабе для встроенных контроллеров, ничего более изящного, чем «настоящая» ОС) подсказывает, что это не так.
4) Все иллюстрации, которые я до сих пор видел, предназначенные для того, чтобы показать, насколько быстрее Node, чем у других веб-серверов, ужасно ошибочны, однако они ошибочны таким образом, что косвенно иллюстрируют одно преимущество, которое я определенно принял бы для Node (и это отнюдь не незначительно). Узел не выглядит так, как будто он нуждается (и даже не разрешает) в настройке. Если у вас есть многопоточная модель, вам нужно создать достаточное количество потоков для обработки ожидаемой нагрузки. Сделайте это плохо, и вы получите плохую производительность. Если потоков слишком мало, то процессор простаивает, но не может принимать больше запросов, создавать слишком много потоков, и вы будете тратить впустую память ядра, а в случае среды Java вы также будете тратить впустую память основной кучи , Теперь для Java тратить кучу - это первый, лучший способ поднять производительность системы, потому что эффективная сборка мусора (в настоящее время это может измениться с G1, но кажется, что жюри все еще находится на этом этапе по крайней мере в начале 2013 года) зависит от наличия большого количества свободной кучи. Итак, есть проблема: настройте его на слишком малое количество потоков, у вас незанятые процессоры и низкая пропускная способность, настройте его на слишком много, и он застрянет другими способами.
5) Есть другой способ, которым я принимаю логику утверждения, что подход Node «быстрее по замыслу», и это - это. В большинстве моделей потоков используется модель переключения контекста с разделением по времени, расположенная поверх более подходящей модели (предупреждение о значении :) и более эффективной модели (не оценка значения). Это происходит по двум причинам: во-первых, большинство программистов, по-видимому, не понимают приоритетное вытеснение, и, во-вторых, если вы изучаете многопоточность в среде Windows, существует временная привязка, нравится вам это или нет (конечно, это подтверждает первый пункт. Примечательно, что в первых версиях Java использовалось приоритетное вытеснение в реализациях Solaris и временная привязка в Windows. Поскольку большинство программистов не понимали и жаловались, что «многопоточность не работает в Solaris» они поменяли модель на временную шкалу везде). В любом случае, суть в том, что временная привязка создает дополнительные (и потенциально ненужные) переключатели контекста. Каждое переключение контекста отнимает процессорное время, и это время эффективно удаляется из работы, которую можно выполнить в реальной работе под рукой. Однако время, затрачиваемое на переключение контекста из-за временного среза, не должно превышать очень небольшой процент от общего времени, если только не происходит что-то довольно странное, и я не вижу причин, чтобы ожидать, что это произойдет в простой веб-сервер). Итак, да, избыточные переключатели контекста, вовлеченные во временную привязку, неэффективны (и это не происходит в и это время эффективно отводится от работы, которую можно выполнить на реальной работе под рукой. Однако время, затрачиваемое на переключение контекста из-за временного среза, не должно превышать очень небольшой процент от общего времени, если только не происходит что-то довольно странное, и я не вижу причин, чтобы ожидать, что это произойдет в простой веб-сервер). Итак, да, избыточные переключатели контекста, вовлеченные во временную привязку, неэффективны (и это не происходит в и это время эффективно отводится от работы, которую можно выполнить на реальной работе под рукой. Однако время, затрачиваемое на переключение контекста из-за временного среза, не должно превышать очень небольшой процент от общего времени, если только не происходит что-то довольно странное, и я не вижу причин, чтобы ожидать, что это произойдет в простой веб-сервер). Итак, да, избыточные переключатели контекста, вовлеченные во временную привязку, неэффективны (и это не происходит впотоки ядра, как правило, кстати, но разница будет в нескольких процентах пропускной способности, а не в виде целых числовых факторов, которые подразумеваются в заявках на производительность, которые часто подразумеваются для Node.
В любом случае, извинения за то, что все это было длинным и грубым, но я действительно чувствую, что обсуждение пока ничего не доказало, и я был бы рад услышать от кого-то в любой из этих ситуаций:
а) реальное объяснение того, почему Node должен быть лучше (помимо двух сценариев, которые я изложил выше, первый из которых (плохая настройка), я считаю, является реальным объяснением всех тестов, которые я видел до сих пор. ([править ], на самом деле, чем больше я об этом думаю, тем больше мне интересно, может ли быть здесь важна память, используемая огромным количеством стеков. Размеры стеков по умолчанию для современных потоков, как правило, довольно велики, но память, выделяемая система событий на основе замыканий будет только тем, что нужно)
б) настоящий эталонный тест, который фактически дает реальную возможность для выбранного многопоточного сервера. По крайней мере, таким образом, я должен был бы перестать верить, что утверждения по сути ложные;> ([править] это, вероятно, гораздо сильнее, чем я предполагал, но я чувствую, что объяснения, приведенные для повышения производительности, в лучшем случае неполны, и показанные критерии являются необоснованными).
Ура, Тоби
select()
происходит быстрее, чем обмен контекста потока.