2009-09-06 3 views
4

Предположим, у меня есть веб-приложение, работающее на S-серверах со средним количеством C-ядер каждый. Мое приложение обрабатывает в среднем R запросов в любой момент. Предполагая, что R примерно в 10 раз больше, чем S * C, выгоды от распространения работы запроса через несколько ядер не будут минимальными, поскольку каждое ядро ​​уже обрабатывает около 10 запросов?Является ли параллельное вычисление важным для веб-разработки?

Если я прав, почему this guy говорит, что параллелизм настолько важен для будущего Python, как язык для веб-разработки?

Я вижу много причин, почему мой аргумент был бы неправильным. Возможно, приложение получает несколько очень сложных запросов, которые превосходят число доступных ядер. Или, может быть, существует большая вариация в сложности запросов, поэтому одному ядру может быть не повезло и ему даются 10 последовательных сложных запросов, в результате некоторые из них занимают гораздо больше времени, чем это разумно. Учитывая, что парень, который написал вышеупомянутое эссе, гораздо более опытным, чем я, я думаю, что есть большой шанс, что я ошибаюсь в этом, но я хотел бы знать, почему.

ответ

4

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

5

В гипотетических условиях, которые вы проектируете, с примерно 10 запросами «в игре» на каждое ядро, если разумно обрабатывать запрос-к-сердечному назначению (возможно, даже простейшая круговая балансировка нагрузки), это просто отлично, если каждый запрос живет на протяжении всей его жизни на одном ядре.

Точка, это только один шанс этого сценария - Трудные запросы, которые могут действительно принести пользу (с точки зрения более низкой задержки) от нескольких серверов за один запрос, являются, альтернативно, альтернативой. Я подозреваю, что на сегодняшнем веб-сайте ваш сценарий более распространен, но было бы неплохо обрабатывать оба вида, а также «пакетные» фоновые обработки ... особенно, поскольку количество ядер (в отличие от скорости каждого ядра) - это то, что растет, и что будет расти в наши дни.

Далеко не от меня, чтобы возразить против мудрости Иакова Каплана-Мосса, но я привык к тому, что у моего работодателя очень хороший параллелизм, более ясный и более явный и непрозрачный, чем он, кажется, защищает - mapreduce for пакетные задания, распределенное хеширование, основанное на подсвечивании для регистрации N бэкэндов, чтобы очертить работу для 1 запроса и тому подобное.

Возможно, мне просто не хватает реального опыта работы с (скажем) Erlang, Scala или сравнительно новой программной оперативной памятью Haskell, чтобы узнать, насколько они великолепно масштабируются для использования десятками или hundrends тысяч ядер на низких QPS, высоких рабочих нагрузках на Q. ... но мне кажется, что серебряная пуля для этого сценария (за вычетом относительно ограниченного подмножества случаев, когда вы можете обратиться к mapreduce, pregel, sharding и т. д.), еще не изобретен ни на одном языке. С явной, тщательно продуманной архитектурой Python, безусловно, не хуже, чем Java, C# или C++ при обработке таких сценариев, по крайней мере, по моему опыту работы.

1

Оговорка: Я только обезжиренное раздел «Concurrency», который, кажется, что вы имеете в виду to.The вопрос, кажется (и это не ново, конечно):

  • Нити Python не запускаются параллельно из-за GIL.
  • Системе со многими ядрами потребуется столько бэкэндов (на практике вы, вероятно, хотите, по крайней мере, потоки 2xN).
  • Системы движутся в сторону увеличения количества сердечников; типичные ПК имеют четыре ядра, и доступные серверные системы с 128 или более ядрами, вероятно, не за горами.
  • Выполнение 256 отдельных процессов на языке Python означает отсутствие общих данных; все приложение и любые загруженные данные реплицируются в каждом процессе, что приводит к массовым потерям памяти.

Последний бит, где эта логика терпит неудачу. В самом деле, если вы начинаете 256 Python-бэкендов наивным способом, данных нет. Тем не менее, это не имеет никакого предусмотрения: это неправильный способ начать много бэкэнд-процессов.

Правильный способ - загрузить все ваше приложение (все модули Python, от которых вы зависите, и т. Д.) В один мастер-процесс. Затем этот мастер-процесс выдает бэкэнд-процессы для обработки запросов. Они становятся отдельными процессами, но стандартное управление памятью на запись означает, что все фиксированные данные уже загружены совместно с мастером. Весь код, который был предварительно загружен мастером, теперь распределяется между всеми работниками, несмотря на то, что все они являются отдельными процессами.

(Конечно, КОРОВА означает, что если вы напишете на него, он создает новую копию данных. - но такие вещи, как скомпилированные байты-код Python не должны быть изменены после загрузки)

Я не знаю, если есть проблемы, связанные с Python, которые предотвращают это, но если это так, то это детали реализации, которые необходимо устранить. Такой подход намного проще реализовать, чем пытаться устранить GIL. Это также исключает возможность возникновения традиционных проблем с блокировкой и резьбой. Это не так плохо, как на некоторых языках и в других случаях использования - практически нет взаимодействия или блокировки между потоками, но они не исчезают полностью, а условия гонки на Python - это такая же боль, как и трек так как они находятся на любом другом языке.

0

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

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

Если он имеет в виду способ улучшения функциональных и асинхронных подходов, то я несколько согласен, но он кажется тангенциальным для его точки «нам нужен лучший параллелизм». Python может иметь это сейчас (что он признает), но, по-видимому, его не очень хорошо достаточно (все из-за GIL, естественно). Честно говоря, это скорее похоже на то, как напасть на GIL, а не на оправдание важности параллелизма в веб-разработке.

Важным моментом в отношении параллелизма и веб-разработки является то, что параллелизм - это hard. Красота чего-то типа PHP заключается в том, что is нет параллелизма. У вас есть процесс, и вы застряли в этом процессе. Это так просто и легко. Вам не нужно беспокоиться о каких-либо проблемах параллелизма - вдруг программирование намного проще.

+0

Err, вы всегда хотите параллелизм для веб-серверов по своей природе - и параллелизм * легко * для веб-серверов на основе FCGI/SCGI, так как вы просто запускаете несколько бэкэнд-процессов. Его аргумент, похоже, является проблемой памяти при использовании процессов вместо потоков (как я описал ранее). –

+0

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

1

Одна вещь, которую вы опускаете, заключается в том, что веб-запрос - это не одна последовательная серия инструкций, в которой задействован только процессор.

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

Я думаю, что даже с помощью GIL Python может запускать другие потоки, пока один поток ожидает ввода-вывода. (Другие процессы, безусловно, могут.) Тем не менее, потоки Python не похожи на потоки Erlang: начните с них достаточно, и это начнет болеть.

Еще одна проблема - память. Библиотеки C разделяются между процессами, но (AFAIK) библиотеки Python не являются. Таким образом, запуск 10-кратного количества процессов Python может сократить ожидания ввода-вывода, но теперь у вас есть 10 копий каждого загружаемого модуля Python для ядра.

Я не знаю, насколько они значительны, но они усложняют ситуацию за пределами «R> 10 * S * C». В мире Python еще многое предстоит сделать, чтобы решить их, потому что это непростые проблемы.

+0

Вы правы - наиболее распространенный пример - это, вероятно, SQL-запросы. Однако это в основном важно для нагрузок, связанных с I/O. Вопрос о масштабировании 128-ядерных машин по своей природе важен для нагрузок, связанных с процессором. (См. Мой ответ для одного подхода к проблеме с общей памятью.) –

Смежные вопросы