Учебник Python/Процессы и потоки


https://docs.google.com/document/d/17fRwg2Sy2WroeQkTaO6hS4FKtwJcq0-l3fj77YMLFW8/pub

Процессы

править

call (первый вариант, попроще)

править
import subprocess
print subprocess.call('python D:/axe/python/easygui/easygui.pyw', shell=True) # запускает. ждёт, пока выполнится. возвращает код завершения

запустить с аргументами:

call( ["ls", "-l"] ) ## первый элемент - название программы, последующие элементы - параметры

Popen (правильный вариант)

править

Модуль subprocess позволяет создавать новые процессы, соединять их в конвееры (когда результат одного подаётся на вход другому).

В реальных условиях бывает лучше создать всего один новый процесс с точки зрения Python (один вызов Popen), которому на вход можно подать строку, содержащую последовательность действий.

from subprocess import Popen, PIPE
proc = Popen(
    "python D:/axe/python/easygui/easygui.pyw",
    shell=True,
    stdout=PIPE, stderr=PIPE
)
proc.wait()    # дождаться выполнения
res = proc.communicate()  # получить tuple('stdout', 'stderr')
if proc.returncode:
    print res[1]
print 'result:', res[0]

PIPE - это технология, которая позволяет выстраивать запуск процессов в цепочки и передавать информацию между ними.

параметр Popen stdin=PIPE - важная штука. если stdin=PIPE, то доступен файловый дескриптор proc.stdin

далее можно делать:

proc.stdin.write('какой-то текст')
proc.close()

можно отправить что-то в stdin через proc.communicate(stdinMsg)

то же самое касается stdout и stderr.

Для proc будут доступны атрибуты proc.stdout и proc.stderr, из которых можно вытащить инфу через proc.stdout.read() можно получить stdout и stderr как результат proc.communicate

Через os

править
import os
a = os.fork() # копирует текущий процесс и возвращает 0, если теперь находимся внутри дочернего процесса, и PID внутри родительского
if a == 0:
    mpathTotest = 'python' # имя исполняемого файла
    args = []
    os.execlp( mpathTotest, *args )
else:
    print 1

другой вариант:

import os
print os.spawnl( os.P_WAIT, 'run.cmd' ) ## spawn создаёт новый процесс. не рекомендуется к использованию, лучше юзать subprocess

multiprocessing

править

Этот модуль позволяет работать с процессами как с потоками.

from subprocess import Popen, PIPE
from multiprocessing import Process, Queue

def execute(queue):
    proc = Popen( "python ./dsTest.py", shell=True, stdout=PIPE )
    proc.wait() # дождаться выполнения
    queue.put(proc.communicate()[0]) ## получить то, что вернул подпроцесс

allProcesses = []
queue = Queue()
for i in xrange(10):
    p = Process(target=execute, args=(queue,))
    allProcesses.append(p)
    p.start()

for p in allProcesses:
    p.join()

for i in xrange( queue.qsize() ):
    print queue.get()

Сигналы

править

Сигналы бывают обрабатываемые и необрабатываемые.

import signal
from signal import SIGINT, SIGTERM

def handler(signo, arg):
    print '*' * 80
    print signo ## int число - номер сигнала
    print arg  ## <frame object> - гугл по этому вопросу советовал посмотреть http://docs.python.org/library/inspect.html
    print '*' * 80
    exit() ## иначе процесс не завершится

signal.signal( SIGINT, handler ) 
signal.signal( SIGTERM, handler )
SIGINT
2

Прерывание работы с клавиатуры по ctrl+c (ctrl+z - приводит к SIGSTOP - необрабатываемый сигнал)

SIGTERM
15

Завершение процесса по

Потоки

править

Простейший пример работы с потоками:

from threading import Thread
from time import sleep

class MyThread(Thread):

    def __init__(self):
        Thread.__init__(self)

    def run(self):
        for i in range(20):
            print self
            sleep(0.222)

c = MyThread()
b = MyThread()
b.setDaemon(True)
c.start()
b.start()
c.join() # дождаться завершения потока в основном потоке
print "finish"

Основной поток ждёт завершения выполнения дочерних потоков, кроме потоков, помеченных как фоновые (b.setDaemon(True)).