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


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

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


1
Я вважаю, що ви шукаєте модуль багатопроцесорної обробки .
Noctis Skytower

Відповіді:


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 Я хочу запустити функцію у фоновому режимі, але у мене є деякі обмеження ресурсів, і я не можу запустити функцію стільки разів, скільки я хочу і хочу поставити в чергу додаткові виконання функції. Чи маєте ви уявлення про те, як мені це робити? У мене тут є своє запитання . Не могли б ви поглянути на моє запитання? Будь-яка допомога була б чудовою!
Амір

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 (), коли це не крос-платформа.
Devin Jeanpierre

3
@ Девін, ти завжди можеш повернути голос проти, який ти зробив, якщо хочеш.
Alex Martelli

Тоді відредаговано, щоб пояснити це. Я прямо зазначив, що forkце не є портативним; Я, як правило, даю непереносні відповіді разом із інформацією про те, що вони не переносяться, і нехай допитувач вирішить, чи достатньо для них цього. Оскільки я відредагував свою відповідь, ви зможете зняти голос проти, якщо вважаєте, що я його достатньо покращив; хоча жодних важких почуттів, якщо ви цього не зробите, я просто хотів перевірити, чи не помилився я.
Брайан Кемпбелл,

@ Алекс, ні, ти не можеш. Через певний проміжок часу ви не зможете повернути його назад, доки не відбудеться редагування. Така кількість часу пройшло, перш ніж я переосмислив, таким чином, коментар "занадто пізно". У будь-якому випадку, як я вже сказав, я вирішив, що воно того не варте, тож його немає. Я також ціную і розумію ваші причини, і я радий, що в будь-якому випадку не виникне жодних переживань. : 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)функцією для негайного фонового потоку.

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