Учебник Python/Процессы и потоки
https://docs.google.com/document/d/17fRwg2Sy2WroeQkTaO6hS4FKtwJcq0-l3fj77YMLFW8/pub
Процессы
[править]subprocess
[править]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
[править]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)).