Является ли максимальное ограничение потока на самом деле неактуальной проблемой для Python/Linux?

Текущее приложение Python, над которым я работаю, требует использования более 1000 потоков (модуль потоков Python). Не то, чтобы какой-либо отдельный поток работал на максимальных циклах процессора, это просто приложение для тестирования нагрузки веб-сервера, которое я создаю. т.е. эмулировать 200 клиентов Firefox, которые все стремятся к веб-серверу и загружают небольшие веб-компоненты, в основном эмулируя людей, которые работают за секунды, а не за микросекунды.

Итак, я читал различные темы, такие как «сколько потоков поддерживает python в Linux / Windows и т. Д.», И я видел много разных ответов. Один пользователь сказал, что все дело в памяти, а ядро ​​​​Linux по умолчанию только выделяет 8Meg для потоков, если он превышает это значение, потоки начинают уничтожаться ядром.

Один парень заявил, что это не проблема для CPython, потому что в любом случае одновременно работает только 1 поток (из-за GIL), поэтому мы можем указать миллион потоков ??? Какова настоящая правда по этому поводу?


person TedBurrows    schedule 27.04.2012    source источник
comment
Рассматривали ли вы возможность использования чего-то вроде Tornado, который может выполнять множество асинхронных HTTP-запросов в одном потоке?   -  person Amber    schedule 27.04.2012
comment
...или просто используйте некоторыевещь, которая уже решила нагрузочное тестирование HTTP.   -  person josh3736    schedule 27.04.2012


Ответы (2)


  1. «Из-за GIL одновременно выполняется один поток». Ну вроде. GIL означает, что только один поток может одновременно выполнять код Python. Однако любое количество потоков может выполнять ввод-вывод, различные другие системные вызовы или другой код, не содержащий GIL.

    Похоже, ваши потоки будут в основном выполнять сетевой ввод-вывод, и любое количество потоков может выполнять ввод-вывод одновременно. Конкуренция GIL может быть довольно жесткой с 1000 потоков, но вы всегда можете создать несколько процессов Python и разделить потоки ввода-вывода между ними (т. е. fork пару раз перед запуском).

  2. «Ядро Linux по умолчанию выделяет только 8 мегабайт для потоков». Я не уверен, где вы это услышали. Возможно, вы на самом деле слышали: «В Linux размер стека по умолчанию часто составляет 8 МБ», и это правда. Каждый поток будет использовать 8 МБ адресного пространства для стека (без проблем на 64-разрядной версии), а также ресурсы ядра для дополнительных карт памяти и самого процесса потока. Вы можете изменить размер стека с помощью библиотечной функции threading.stack_size, которая помогает, если у вас много потоков, которые не выполняют глубокие вызовы.

    >>> import threading
    >>> threading.stack_size()
    0 # platform default, probably 8 MiB
    >>> threading.stack_size(64*1024) # 64 KiB stack size for future threads
    
  3. Другие в этом потоке предложили использовать асинхронную/неблокирующую структуру. Ну, ты можешь это сделать. Однако в современном ядре Linux многопоточная модель конкурирует с асинхронными (select/poll/epoll) методами мультиплексирования ввода-вывода. Переписать код для использования асинхронной модели — нетривиальный объем работы, поэтому я бы сделал это только в том случае, если бы не смог получить требуемую производительность от поточной модели. Если ваши потоки действительно пытаются имитировать человеческую задержку (например, проводят большую часть своего времени во сне), существует множество сценариев, в которых асинхронный подход на самом деле медленнее. Я не уверен, что это применимо к Python, где одно только уменьшение конкуренции GIL может заслуживать переключения.

person Dietrich Epp    schedule 27.04.2012
comment
На моей машине с Linux размер стека установлен на 10 МБ. Это слишком много для такого количества потоков. Я ввожу ulimit -s 1024, и теперь я могу открыть сотни потоков. Мне нужно взглянуть на этот пример и посмотреть, смогу ли я просто поместить это в свой скрипт Python. Спасибо. - person TedBurrows; 02.05.2012

Оба они частично верны:

  • У каждого потока есть стек, и вы можете исчерпать адресное пространство для стека, если создадите достаточно потоков.

  • В Python также есть что-то, называемое GIL, которое позволяет одновременно запускать только один поток Python. Однако, как только код Python вызывает код C, этот код C может выполняться во время выполнения другого потока Python. Однако потоки в Python по-прежнему являются физическими, и по-прежнему существует ограничение на размер стека.

Если вы планируете иметь много подключений, а не использовать много потоков, рассмотрите возможность использования асинхронного дизайна. Twisted, вероятно, подойдет здесь.

person icktoofay    schedule 27.04.2012
comment
Если вы решите использовать Twisted, у него есть клиентский модуль HTTP (документы). - person icktoofay; 27.04.2012
comment
gevent выглядит как альтернатива Twisted. - person icktoofay; 27.04.2012