Чи варто дотримуватися або відмовитися від Python, щоб мати справу з одночасністю?


31

У мене є проект на 10-ти локальний LOC, написаний у Django з великою кількістю селери ( RabbitMQ ) для асинхронності та фонових завдань, де потрібно, і я дійшов висновку, що частини системи виграють від того, щоб переписати щось інше, ніж Django для кращої одночасності . Причини включають:

  • Обробка сигналів та змінні об'єкти. Особливо, коли один сигнал спрацьовує інший, обробка їх у Django за допомогою ORM може бути дивовижною, коли екземпляри змінюються або зникають. Я хочу скористатися деяким підходом до обміну повідомленнями, коли передані дані не змінюються в обробниках ( підхід Clojure при копіюванні при записі здається приємним, якщо я правильно зрозумів).
  • Частини системи не базуються на веб-сторінках і потребують кращої підтримки для виконання завдань одночасно. Наприклад, система зчитує теги NFC , і коли один зчитується світлодіод увімкнено протягом декількох секунд (завдання із селери), відтворюється звук (інше завдання Селери), а база даних запитується (інше завдання). Це реалізується як команда управління Django, але Django та її ORM є синхронними за своєю природою та обміном пам'яттю обмежують (ми думаємо додати більше читачів NFC, і я не думаю, що підхід Django + Celery буде працювати більше, Я хотів би бачити кращі можливості передачі повідомлень).

Які плюси та мінуси використання чогось на кшталт Twisted або Tornado у порівнянні з мовою на зразок Erlang або Clojure ? Мене цікавлять практичні переваги та шкода.

Як ви прийшли до висновку, що деякі частини системи краще їздять іншою мовою? Ви відчуваєте проблеми з роботою? Наскільки серйозні ці проблеми? Якщо це може бути швидше, чи важливо, щоб воно було швидше?

Приклад 1: Django на роботі поза HTTP-запитом:

  1. Зчитується тег NFC.
  2. База даних (і, можливо, LDAP) запитується, і ми хочемо щось зробити, коли дані стануть доступними (червоне або зелене світло, відтворити звук). Це блокує використання Django ORM, але поки є в наявності працівники селери, це не має значення. Можливо, проблема з більшою кількістю станцій.

Приклад 2: "передача повідомлення" за допомогою сигналів Джанго:

  1. post_deleteПодія обробляється, інші об'єкти можуть бути змінені або видалені з - за цього.
  2. Наприкінці сповіщення слід надсилати користувачам. Тут було б добре, якби аргументи, передані обробнику повідомлень, були копіями видалених або видалених об'єктів і гарантовано не змінювали обробник. (Це можна зробити вручну просто, не передаючи, звичайно, об'єкти, якими керує ORM, обробникам.)

Я думаю, що кращі відповіді будуть, якщо ви поясните більше, чому ви дійшли висновку
Вінстон Еверт

5
Перш ніж хтось скаже, що питання вибору мови є позатематичним, я прозвучу, кажу, що це добре, оскільки це практична проблема з конкретними вимогами. Я сподіваюся, що вона проводить деякі детальні порівняння.
Адам Лір

Скручений - це протилежність одночасно! Це єдиний потоковий сервер, керований подіями, він нікуди не дістанеться, якщо вам потрібна справжня паралельність.

Відповіді:


35

Відкриття думок

Як ви прийшли до висновку, що деякі частини системи краще їздять іншою мовою? Ви відчуваєте проблеми з роботою? Наскільки серйозні ці проблеми? Якщо це може бути швидше, чи важливо, щоб воно було швидше?

Асинхронія з однонитковою стрічкою

Існує кілька питань та інших веб-ресурсів, які вже вирішують відмінності, плюси та мінуси однопотокової асинхронії та одночасності багатопотокових. Цікаво читати про те, як працює асинхронна модель Node.js з однопоточним зв’язком, коли введення-виведення є основним вузьким місцем, і одразу існує багато багатьох запитів.

Скручені, Торнадо та інші асинхронні моделі відмінно використовують однониткові. Оскільки у багатьох веб-програмуваннях є багато вводу-виводу (мережа, база даних тощо), час, витрачений на очікування віддалених дзвінків, значно збільшується. Це час, який можна витратити на інші речі - наприклад, відхилення інших дзвінків до бази даних, надання сторінок та генерування даних. Використання цієї однониткової надто великої кількості.

Однією з найбільших переваг однопотокової асинхронії є те, що вона використовує набагато менше пам'яті. У багатопотоковому виконанні кожен потік вимагає певної кількості зарезервованої пам'яті. Зі збільшенням кількості потоків збільшується і обсяг пам'яті, необхідний лише для існування потоків. Оскільки пам’ять обмежена, це означає, що існує кількість меж потоку, які можна створити будь-коли.


Приклад

Що стосується веб-сервера, зробіть вигляд, що кожному запиту надається власний потік. Скажімо, для кожного потоку потрібно 1 Мб пам'яті, а веб-сервер має 2 Гб оперативної пам’яті. Цей веб-сервер зможе обробити (приблизно) 2000 запитів в будь-який момент часу, перш ніж просто не вистачить пам'яті для обробки.

Якщо ваше навантаження значно вище, ніж це, запити знадобляться дуже довго (коли очікуєте завершення старих запитів), або вам доведеться закидати більше серверів у кластер, щоб розширити кількість можливих одночасних запитів .


Паралельність багатопотокових

Паралельність із декількома потоками покладається на виконання декількох завдань одночасно. Це означає, що якщо нитка заблокована, очікуючи на виклик бази даних, щоб повернутися, інші запити можуть бути оброблені одночасно. Використання ниток є нижчим, але кількість виконуваних потоків значно більша.

Багатопотоковий код також набагато складніше міркувати. Існують проблеми із блокуванням, синхронізацією та іншими проблемами веселої одночасності. Однопоточна асинхронія не страждає від однакових проблем.

Однак багатопотоковий код набагато ефективніший для процесорів, що інтенсивно працюють . Якщо немає можливості для потоку «поступатись» (наприклад, мережевий дзвінок, який зазвичай блокується), однопотокова модель просто не матиме жодної однорідності.

Обидва можуть співіснувати

Звичайно, між ними перекриваються; вони не є взаємовиключними. Наприклад, багатопотоковий код можна записати не блокуючим способом, щоб краще використовувати кожен потік.


Суть

Є багато інших питань, які слід розглянути, але мені подобається думати про такі два:

  • Якщо ваша програма пов'язана з входом / виводом , то однонитка асинхронія, ймовірно, буде працювати досить добре.
  • Якщо ваша програма пов'язана з процесором , то, мабуть, найкраща буде багатопотокова система.

У вашому конкретному випадку вам потрібно визначити, який вид асинхронної роботи виконується, і як часто ці завдання виникають.

  • Чи трапляються вони на кожен запит? Якщо це так, пам'ять, ймовірно, стане проблемою у міру збільшення кількості запитів.
  • Чи замовлені ці завдання? Якщо це так, вам доведеться розглянути можливість синхронізації, якщо використовувати декілька потоків.
  • Ці завдання CPU є інтенсивними? Якщо так, чи здатна однонитка не відставати від навантаження?

Немає простої відповіді. Ви повинні врахувати, якими є випадки використання, та спроектувати їх відповідно. Іноді краще асинхронна однопоточна модель. В інших випадках потрібно використовувати ряд ниток для досягнення масивної паралельної обробки.

Інші міркування

Є й інші питання, які потрібно також врахувати, а не просто модель одночасності, яку ви обрали. Ви знаєте Ерланга чи Клуджура? Як ви думаєте, ви могли б написати безпечний багатопотоковий код однією з цих мов, щоб покращити продуктивність вашої програми? Чи знадобиться багато часу, щоб швидко набратися однією з цих мов, і чи допоможе вам мова в майбутньому?

Як щодо труднощів, пов’язаних із спілкуванням між цими двома системами? Чи буде надмірно складним підтримувати дві окремі системи паралельно? Як система Erlang отримає завдання від Django? Як Ерланг передасть ці результати назад до Джанго? Чи досить продуктивність є проблемою, що варте додаткової складності?


Фінальні думки

Я завжди вважав, що Джанго є досить швидким, і його використовують деякі сайти, де дуже торгують людьми. Ви можете зробити кілька оптимізацій продуктивності, щоб збільшити кількість паралельних запитів та часу відповіді. Щоправда, я досі нічого не робив із селерою, тому звичайні оптимізації продуктивності, ймовірно, не вирішать жодних проблем, які можуть виникнути з цими асинхронними завданнями.

Звичайно, завжди є можливість кинути більше обладнання на вирішення проблеми. Чи дешевше забезпечення нового сервера дешевше, ніж вартість розробки та обслуговування абсолютно нової підсистеми?

На сьогодні я задав занадто багато питань, але це був мій намір. Відповідь не буде простою без аналізу та додаткових деталей. Вміння проаналізувати проблеми зводиться до того, щоб знати питання, які потрібно задати, але, сподіваюся, я допоміг на цьому фронті.

Моє відчуття кишки говорить про те, що переписувати іншою мовою не потрібно. Складність та вартість, ймовірно, будуть занадто великими.


Редагувати

Відповідь на подальші дії

У подальшому поданні представлено кілька дуже цікавих випадків використання.


1. Django, що працює поза HTTP-запитами

Ваш перший приклад включав читання тегів NFC, а потім запит до бази даних. Я не думаю, що написання цієї частини іншою мовою буде для вас корисним, просто тому, що запит до бази даних або сервера LDAP буде пов'язаний мережевим входом / виводом (і, можливо, продуктивністю бази даних). З іншого боку, кількість одночасних запитів буде пов'язана самим сервером, оскільки кожна команда управління буде виконуватися як власний процес. Настане час налаштування та час виходу, який впливає на продуктивність, оскільки ви не надсилаєте повідомлення вже запущеному процесу. Однак ви зможете надсилати кілька запитів одночасно, оскільки кожен процес буде ізольованим.

У цьому випадку я бачу два шляхи, які ви можете дослідити:

  1. Переконайтеся, що ваша база даних здатна обробляти декілька запитів одночасно з об'єднанням з'єднань. (Наприклад, Oracle вимагає відповідно налаштувати Django 'OPTIONS': {'threaded':True}.) На рівні бази даних або на рівні Django можуть бути подібні параметри конфігурації, які можна налаштувати для власної бази даних. Незалежно від того, якою мовою ви пишете запити до бази даних, вам доведеться чекати, коли ці дані повернуться, перш ніж ви зможете засвітити світлодіоди. Виконання коду запиту може змінити значення, і Django ORM не блискавично ( але , як правило, досить швидко).
  2. Мінімізуйте час налаштування / відстеження. Постійно виконуйте процес і надсилайте до нього повідомлення. (Виправте мене, якщо я помиляюся, але саме на цьому фокусується ваше первісне запитання.) Чи цей процес написано на Python / Django чи іншою мовою / рамкою, висвітлено вище. Мені не подобається так часто використовувати команди управління. Чи можливо постійно працювати невеликий шматок коду, який штовхає повідомлення читачів NFC на чергу повідомлень, яку потім Селері читає і передає Джанго? Налаштування та припинення невеликої програми, навіть якщо вона написана на Python (але не Django!), Має бути кращою, ніж запуск та зупинення програми Django (з усіма її підсистемами).

Я не впевнений, який веб-сервер ви використовуєте для Django. mod_wsgiдля Apache дозволяє налаштувати кількість процесів і потоків у межах процесів, які запитує служба. Не забудьте налаштувати відповідну конфігурацію вашого веб-сервера, щоб оптимізувати кількість справних запитів.


2. "Повідомлення" із сигналами Джанго

Ваш другий випадок використання також досить цікавий; Я не впевнений, чи маю на це відповіді. Якщо ви видаляєте екземпляри моделей і хочете оперувати ними пізніше, можливо, можливо їх серіалізувати, JSON.dumpsа потім десеріалізувати JSON.loads. Пізніше повністю відтворити графік об'єкта буде неможливо (запит пов'язаних моделей), оскільки пов'язані поля ледаче завантажуються з бази даних, і це посилання більше не буде існувати.

Іншим варіантом було б якось позначити об’єкт для видалення та видалити його лише в кінці циклу запиту / відповіді (після того, як усі сигнали будуть обслужені). Для здійснення цього може знадобитися спеціальний сигнал, а не покладатися на нього post_delete.


1
багато FUD та сумнівів щодо блокування та інших речей, які не стосуються Erlang, жодна з перелічених вами традиційних спільних державних проблем - це міркування з мовою та часом виконання, спеціально розробленими для того, щоб не ділитись державою. Erlang може впоратися з десятками тисяч стриманих процесів за дуже мало оперативної пам’яті, а також тиск у пам’яті не є проблемою.

@Jarrod, я особисто не знаю Ерланг, тому я прийму те, що ви говорите з цього приводу. Інакше майже все інше, про що я згадував, є актуальним. Вартість, складність та правильне використання поточних інструментів чи ні.
Джош Смітон


Це така епічна відповідь, яку я дуже люблю читати ^^. +1, хороша робота!
Лоран Буро-Рой

Також якщо у вас є шаблони DJango, їх можна використовувати в ерланге з Erlydtl
Zachary K

8

Я зробив кілька дуже складних високо масштабованих розробок для великого провайдера США . Ми зробили кілька серйозних номерів транзакцій за допомогою сервера Twisted , і це був кошмар складності, щоб отримати Python / Twisted для масштабування на будь-що, що було пов'язане з процесором . Зв'язок вводу / виводу - це не проблема, але пов'язати процесор було неможливо. Ми могли б швидко зібрати системи, але залучення їх до масштабів мільйонів одночасних користувачів було кошмаром конфігурації та складності, якщо їх пов'язував процесор.

Я написав про це повідомлення в блозі, Python / Twisted VS Erlang / OTP .

TLDR; Ерланг переміг.


4

Практичні проблеми з Twisted (які я люблю і використовую близько п’яти років):

  1. Документація залишає бажати кращого, а модель навчитися все-таки досить складно. Мені важко змусити інших програмістів Python працювати над Twisted-кодом.
  2. Я в кінцевому рахунку використовував блокування вводу / виводу файлів і доступу до бази даних через відсутність хороших API блокування. Це може дуже зашкодити продуктивності.
  3. Здається, не існує величезної громади та здорової громади, яка використовує Twisted; наприклад, Node.js має набагато активніший розвиток, особливо для веб-бек-енд програмування.
  4. Це все ще Python, і принаймні CPython - не найшвидша річ навколо.

Я трохи попрацював, використовуючи Node.js з CoffeeScript, і якщо паралельна продуктивність викликає стурбованість, то, можливо, варто скочити.

Чи розглядали ви запускати кілька екземплярів Django з певною домовленістю поширювати клієнтів між екземплярами?


1
Python документації в цілому залишає бажати кращого: / (Не кажучи це , що погано, але для мови , який популярний один було б очікувати , що це буде набагато краще).
Грак

3
Я вважаю, що документація Python і, зокрема, документація Django є одними з найкращих документів на будь-які мовні рухи. У багатьох сторонніх бібліотеках все ж залишається бажати кращого.
Джош Смітон

1

Я пропоную наступне, перш ніж розглянути можливість переходу на іншу мову.

  1. Використовуйте LTTng для запису системних подій, таких як помилки сторінки, контекстні комутатори та очікування системного виклику.
  2. Перетворіть де завгодно, щоб зайняти занадто багато часу для використання бібліотеки С, і використовуйте будь-який шаблон дизайну, який вам подобається (багатопотокова передача, на основі сигнальних подій, асинхронний дзвінок або традиційний Unix select), що добре для вводу / виводу там.

Я б не використовував потоки в Python, як тільки програма має пріоритет у виконанні. Я б взяв вищевказаний варіант, який може вирішити багато проблем, таких як повторне використання програмного забезпечення, зв'язок з Django , продуктивність, простота розробки тощо.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.