#python #concurrency #subprocess
#python #параллелизм #подпроцесс
Вопрос:
Чего я пытаюсь достичь, так это транслировать твиты из Twitter в течение часа, записывать список твитов в файл, очищать и запускать анализ для последнего часа твитов, а затем повторять процесс бесконечно.
Проблема, с которой я сталкиваюсь, заключается в том, что если я запускаю очистку и анализ твитов в том же скрипте, который обрабатывает потоковую передачу, — либо жестко запрограммировав его, либо импортировав функциональность из модуля, — весь скрипт ожидает завершения этих процедур, а затем снова начинает потоковую передачу. Есть ли способ вызвать модуль очистки и анализа в потоковом скрипте, чтобы они выполнялись одновременно, и потоковая передача не прекращалась, пока происходит очистка и анализ?
Я пытался добиться этого с помощью subprocess.call('python cleaner.py', shell=True)
and subprocess.Popen('python cleaner.py', shell=True)
, но я действительно не знаю, как правильно использовать эти инструменты, и два примера выше привели к остановке потоковой передачи, cleaner.py
запуску, а затем возобновлению потоковой передачи.
Ответ №1:
Подпроцесс
Вы можете использовать subprocess.Popen
, как вы пытались, для одновременного запуска другого скрипта:
the_other_process = subprocess.Popen(['python', 'cleaner.py'])
Только эта строка делает то, что вы хотите. Чего вы не хотите делать, так это:
the_other_process.communicate()
# or
the_other_process.wait()
Это остановит текущий процесс и будет ждать завершения другого. Очень полезная функция в других обстоятельствах.
Если вы хотите знать, завершен ли подпроцесс (но не ждать его):
result = the_other_process.poll()
if result is not None:
print('the other process has finished and retuned %s' % result)
Нитки
Параллелизм также может быть достигнут с помощью потоков. В этом случае вы не запускаете новый процесс, вы просто разделяете текущий процесс на параллельные части. Попробуйте это:
def function_to_be_executed_concurrently():
for i in range(5):
time.sleep(1)
print('running in separate thread', i)
thread = threading.Thread(target=function_to_be_executed_concurrently)
thread.start()
for i in range(5):
time.sleep(1)
print('running in main thread', i)
Приведенный выше код должен приводить к смешанным выводам running in separate thread
и running in main thread
.
Поток против процесса
- Используя
subprocess
, вы можете запускать все, что может быть запущено автономно из оболочки. Это не обязательно должен быть python. - Используя
threading
, вы можете запускать любую функцию в параллельном потоке выполнения. - Потоки используют одну и ту же память, поэтому между ними легко обмениваться данными (хотя есть проблемы, когда требуется синхронизация). С процессами совместное использование данных может стать проблемой. Если требуется совместное использование большого количества данных, процессы susb могут быть намного медленнее.
- Запуск нового процесса происходит медленнее и потребляет больше ресурсов, чем запуск потока
- Поскольку потоки выполняются в одном и том же процессе, их общий доступ привязан к одному и тому же GIL, что означает, что большинство вещей будет выполняться на одном и том же ядре процессора. Если необходимо ускорить выполнение очень медленных задач, требующих больших затрат ресурсов процессора, выполнение их в отдельных процессах будет быстрее.
Многопроцессорная обработка
multiprocessing
модуль предоставляет интерфейс, аналогичный threading
, но вместо этого он запускает подпроцессы. Это полезно, когда вам нужно в полной мере использовать все ядра процессора.
** Обратите внимание, что subprocess.Popen(['python', 'cleaner.py'])
это то же самое, subprocess.Popen('python cleaner.py', shell=True)
что и, но первое лучше изучить.
Например, если в пути есть пробел, это приведет к сбою:
subprocess.Popen('python My Documents\cleaner.py', shell=True)
Это не удается, потому что он интерпретирует My
и Documentscleaner.py
как два отдельных аргумента.
С другой стороны, это будет работать так, как ожидалось:
subprocess.Popen(['python', 'My Documents\cleaner.py'])
Это работает, потому что аргументы явно разделяются с помощью списка.
Последнее особенно полезно, если один из аргументов находится в переменной:
subprocess.Popen(['python', path_to_file])
Комментарии:
1. Большое вам спасибо за ваш ответ. Рад узнать, что я был на правильном пути. Вы говорите, что ‘shell = True’ не меняет способ ‘подпроцесса. Popen
2. ‘подпроцесс. Метод Popen’ работает в моем экземпляре, но не могли бы вы подробнее рассказать о том, что он делает ? (Извините за сложный комментарий, я опубликовал первый фрагмент случайным щелчком мыши и не смог придумать, как его удалить или отредактировать)
3. @alvalentini я добавил объяснение
shell=True
к ответу