Python进程和线程

发布时间:2017-09-03 11:37:23
Python进程和线程

这篇断断续续学了一个月,已经陷入部分遗忘的状态了,好多是直接从廖老师的教程中贴过来的,还需要再消化消化。

1. 多进程

Python的os模块封装了常见的系统调用,其中就包括fork,可以通过fork创建子进程。该功能只能运行于Unix/Linux/Mac系统,Windows系统无法运行。

fork()函数调用一次,返回两次。父进程的返回子进程的id,子进程的返回0。

import os print('Process (%s) start...' % os.getpid()) # Only works on Unix/Linux/Mac: pid = os.fork() if pid == 0: print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())) else: print('I (%s) just created a child process (%s).' % (os.getpid(), pid))

os.getpid()获取当前进程id。

os.getppid()获取当前进程的父进程id。

multiprocessing模块是跨平台的多进程模块。提供了一个Process类来代表一个进程对象:

from multiprocessing import Process import os # 子进程要执行的代码 def run_proc(name): print('Run child process %s (%s)...' % (name, os.getpid())) if __name__=='__main__': print('Parent process %s.' % os.getpid()) p = Process(target=run_proc, args=('test',)) print('Child process will start.') p.start() p.join() print('Child process end.')

创建子进程需要传入一个执行函数和对应参数构造Process实例,用start()方法启动,用join()方法可以等待子进程结束后再往下进行,可用于进程同步。

如果要启动很多进程,可以使用进程池批量创建子进程:

from multiprocessing import Pool import os, time, random def long_time_task(name): print('Run task %s (%s)...' % (name, os.getpid())) start = time.time() time.sleep(random.random() * 3) end = time.time() print('Task %s runs %0.2f seconds.' % (name, (end - start))) if __name__=='__main__': print('Parent process %s.' % os.getpid()) p = Pool(4) for i in range(5): p.apply_async(long_time_task, args=(i,)) print('Waiting for all subprocesses done...') p.close() p.join() print('All subprocesses done.')

Pool对象的join()方法会等待所有子进程执行完毕,调用join()之前必须调用close(),而调用close()之后就不能创建新的进程了。

Pool的默认大小是CPU的核数。

subprocess模块可以用来创建子进程并控制其输入输出:

import subprocess print('$ nslookup ') r = subprocess.call(['nslookup', '']) print('Exit code:', r)

这和在命令行上直接 执行

nslookup

是一样的。

如果需要输入,可以通过communicate()方法:

import subprocess print('$ nslookup') p = subprocess.Popen(['nslookup'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, err = p.communicate(b'set q=mx\npython.org\nexit\n') print(output.decode('utf-8')) print('Exit code:', p.returncode)

相当于运行了nslookup命令后手动输入了:

seq q=mx python.org exit

进程间可以通过多种方式来通信,multiprocessing模块提供了Queue、Pipe等方式。

以Queue为例,创建两个子进程,一个写数据,一个读数据:

from multiprocessing import Process, Queue import os, time, random # 写数据进程执行的代码: def write(q): print('Process to write: %s' % os.getpid()) for value in ['A', 'B', 'C']: print('Put %s to queue...' % value) q.put(value) time.sleep(random.random()) # 读数据进程执行的代码: def read(q): print('Process to read: %s' % os.getpid()) while True: value = q.get(True) print('Get %s from queue.' % value) if __name__=='__main__': # 父进程创建Queue,并传给各个子进程: q = Queue() pw = Process(target=write, args=(q,)) pr = Process(target=read, args=(q,)) # 启动子进程pw,写入: pw.start() # 启动子进程pr,读取: pr.start() # 等待pw结束: pw.join() # pr进程里是死循环,无法等待其结束,只能强行终止: pr.terminate()

在windows下,父进程的所有对象都必须通过pickle序列化再传到子进程去。

2. 多线程

一个进程可以由多个线程组成。Python提供对线程的支持,且是真正的Posix Thread,而非模拟出来的线程。

Python提供了两个模块:_thread低级模块和threading高级模块,对_thread模块进行了封装。绝大多数情况使用threading模块就可以了。

启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行:

import time, threading # 新线程执行的代码: def loop(): print('thread %s is running...' % threading.current_thread().name) n = 0 while n < 5: n = n + 1 print('thread %s >>> %s' % (threading.current_thread().name, n)) time.sleep(1) print('thread %s ended.' % threading.current_thread().name) print('thread %s is running...' % threading.current_thread().name) t = threading.Thread(target=loop, name='LoopThread') t.start() t.join() print('thread %s ended.' % threading.current_thread().name)

企业建站2800元起,携手武汉肥猫科技,做一个有见地的颜值派!更多优惠请戳:武汉网站制作 http://www.feimao666.com