Как вызвать один скрипт и одновременно запустить другой в python?

#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 к ответу