Можно ли запустить функцию в подпроцессе без потоковой передачи или написания отдельного файла / скрипта.

83
import subprocess

def my_function(x):
    return x + 100

output = subprocess.Popen(my_function, 1) #I would like to pass the function object and its arguments
print output 
#desired output: 101

Я нашел только документацию по открытию подпроцессов с использованием отдельных скриптов. Кто-нибудь знает, как передать объекты функции или даже простой способ передать код функции?

Wroscoe
источник
1
Я считаю, что вы ищете модуль многопроцессорности .
Ноктис Скайтауэр,

Ответы:

112

Я думаю, вы ищете что-то более похожее на модуль многопроцессорности:

http://docs.python.org/library/multiprocessing.html#the-process-class

Модуль подпроцесса предназначен для создания процессов и выполнения действий с их вводом / выводом, а не для запуска функций.

Вот multiprocessingверсия вашего кода:

from multiprocessing import Process, Queue

# must be a global function    
def my_function(q, x):
    q.put(x + 100)

if __name__ == '__main__':
    queue = Queue()
    p = Process(target=my_function, args=(queue, 1))
    p.start()
    p.join() # this blocks until the process terminates
    result = queue.get()
    print result
Брайан МакКенна
источник
20
Вы можете использовать processifyдекоратор как ярлык: gist.github.com/2311116
schlamar
3
Я предполагаю, что это клонирует интерпретатор Python и все его окружение для подпроцесса?
Йенс
1
Вот форк processify, который работает в Python 3 и поддерживает функции генератора. gist.github.com/stuaxo/889db016e51264581b50
Стюарт Аксон,
4
Обратите внимание, что этот код содержит тупик на случай, если вы передаете нетривиально большие данные через очередь - всегда queue.get () перед присоединением к процессу, в противном случае он будет зависать при попытке записи в очередь, пока ничего не читает.
Петр
@schlamar Я хочу запустить функцию в фоновом режиме, но у меня есть некоторые ограничения на ресурсы, и я не могу запускать функцию столько раз, сколько хочу, и хочу поставить в очередь дополнительные выполнения функции. Ты хоть представляешь, как мне это сделать? У меня есть вопрос здесь . Не могли бы вы взглянуть на мой вопрос? Любая помощь была бы замечательной!
Amir
17

Вы можете использовать стандартный forkсистемный вызов Unix , например os.fork(). fork()создаст новый процесс с тем же запущенным скриптом. В новом процессе он вернет 0, в то время как в старом процессе он вернет идентификатор нового процесса.

child_pid = os.fork()
if child_pid == 0:
  print "New proc"
else:
  print "Old proc"

Для библиотеки более высокого уровня, которая обеспечивает поддержку многопроцессорности, которая предоставляет переносимую абстракцию для использования нескольких процессов, есть модуль многопроцессорности . Есть статья о IBM DeveloperWorks, Многопроцессорная обработка с Python , с кратким введением в оба метода.

Брайан Кэмпбелл
источник
Мне любопытно; почему голос против? Что-то не так в моем ответе?
Брайан Кэмпбелл,
Многопроцессорность - это не просто оболочка более высокого уровня для fork (), это многоплатформенный набор инструментов для многопроцессорной обработки (который использует fork в unix). Это важно, потому что это означает, что он работает, скажем, в Windows, а fork () - нет. Изменить: и это было причиной отрицательного голоса, хотя позже я решил, что это, вероятно, того не стоило. Но уже поздно забирать это обратно. Edit2: Или, скорее, причиной было предложение fork (), когда это не кроссплатформенность.
Девин Жанпьер,
3
@Devin, ты всегда можешь отозвать свой голос против, если хочешь.
Alex Martelli
Отредактировано, чтобы прояснить это. Я прямо упомянул, что forkэто не переносимо; Обычно я даю непереносимые ответы вместе с информацией о том, что они непереносимы, и позволяю спрашивающему решить, достаточно ли этого для них. Поскольку я редактировал свой ответ, вы сможете удалить отрицательный голос, если считаете, что я его достаточно улучшил; хотя никаких обид, если вы этого не сделаете, я просто хотел проверить, что я сделал не так.
Брайан Кэмпбелл,
@ Alex, нет, ты не можешь. По прошествии определенного времени вы не сможете вернуть его, пока не произойдет редактирование. Прошло столько времени, прежде чем я переосмыслил, отсюда и комментарий «слишком поздно». В любом случае, как я уже сказал, я решил, что оно того не стоит, поэтому его больше нет. Я также ценю и понимаю ваши причины, и я рад, что в любом случае не будет обид. : p
Девин Жанпьер
5

Пост Брайана Маккенны о многопроцессорности, приведенный выше, действительно полезен, но если вы хотите пойти по многопоточному маршруту (в отличие от процесса на основе), этот пример поможет вам начать:

import threading
import time

def blocker():
    while True:
        print "Oh, sorry, am I in the way?"
        time.sleep(1)

t = threading.Thread(name='child procs', target=blocker)
t.start()

# Prove that we passed through the blocking call
print "No, that's okay" 

Вы также можете использовать эту setDaemon(True)функцию для немедленного фонового отображения потока.

Алексис Бенуа
источник