介绍进程、线程的概念、多进程和多线程的区别、python中对多进程和多线程的不同的实现方式。
一、进程
进程简单地说是一个程序在计算机系统中执行的一个过程,是操作系统资源分配的基本单位,从更深的层面讲,是操作系统的一种抽象。如你在电脑上运行了QQ这个软件,这就是一个进程。
二、线程
然而,一个程序中往往不止一个逻辑单元,而是存在多个不同导向的代码模块。如,你可以运行QQ一边给一个人传文件一边和另外一个人聊天,聊天和传文件就是一个进程中执行不同功能(也就是不同导向的逻辑单元)模块,这就是线程。也就是说,线程是比进程更小的单位,它们是CPU能够调度的基本单位,同一个进程内部,所有线程共享资源。
三、多进程和多线程的区别
这里只说最重要的两个区别:1、多进程每个进程都要分配相应的资源,而同一个进程的多个线程资源是共享的;2、进程之间的通信需要借助中介,而同一进程的线程之间可以直接通信。
四、python对于多进程的实现
1、基本实现方式
实现方式主要是利用multiprocessing模块(os模块的fork方法也可以,但那只在unix/linux环境下有效,且是复制父进程,应用面太窄)。对于少量的进程,可以对模块中的Process类传入想要运行的方法及方法的参数,然后调运该对象的start方法即可。对于较多的进程,可以创建进程池,即先实例化一个Pool对象,然后调用该对象的apply_async方法,该方法的参数同样是想要执行的方法和该方法的参数。
使用Process类
import os
from multiprocessing import Process
def run_proc(name):
print 'Child process %s (%s) Running...' % (name, os.getpid())
if __name__ == '__main__':
print 'Parent process %s.' % os.getpid()
p_list=[]
for i in range(5):
p = Process(target=run_proc, args=(str(i),))
p_list.append(p)
print 'Process will start.'
p_list[i].start()
for p in p_list:
p.join()
print 'Process end.'
使用Pool类
from multiprocessing import Pool
import os, time, random
def run_task(name):
print 'Task %s (pid = %s) is running...' % (name, os.getpid())
time.sleep(random.random() * 3)
print 'Task %s end.' % name
if __name__=='__main__':
print 'Current process %s.' % os.getpid()
p = Pool(processes=3)
for i in range(5):
p.apply_async(run_task, args=(i,))
print 'Waiting for all subprocesses done...'
p.close()
p.join()
print 'All subprocesses done.'
2、进程间的通信
进程间的同信必须借助媒介,这里主要介绍Queue,同样是来自multiprocessing模块的Queue类,该类本质就是数据结构中的队列,可以由父进程实例化一个对象,传递给各个子进程,或者将其公布在网络上,由各个进程同步到进程内部,再进行读取。
五、python对于多线程的实现
1、实现方法与多进程类似,只是它这里是通过threading模块的Thread类。
2、多线程的锁
之前说过,一个进程内的多个线程是共享资源,有些数据只能允许单个线程修改,这里就要用到同步锁。简而言之,在进程类实例化一个threading.RLock()对象,在对数据修改前使用acquire方法获取资源,完成操作后,使用release方法释放资源。
同步锁例子
import threading
mylock = threading.RLock()
num=0
class myThread(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self,name=name)
def run(self):
global num
while True:
mylock.acquire()
print '%s locked, Number: %d'%(threading.current_thread().name, num)
if num>=4:
mylock.release()
print '%s released, Number: %d'%(threading.current_thread().name, num)
break
num+=1
print '%s released, Number: %d'%(threading.current_thread().name, num)
mylock.release()
if __name__== '__main__':
thread1 = myThread('Thread_1')
thread2 = myThread('Thread_2')
thread1.start()
thread2.start()
Tips1:全局解释器锁(GIL)
python同一个进程内的多个线程无法使用多个CPU,一个进程只能一个核,无论该进程有多少线程,这是语言解释器层面的约束,无法通过第三方库来解决。所以对于计算密集型的程序要使用多进程,而对于网络IO 密集型的操作可以使用多线程。
Tips2:join方法
无论是多线程还是多进程,我们都用到了一个方法join,该方法的作用是进/线程同步。当进/线程执行该方法时,会阻塞其他进/线程,当自身执行完之后才允许其他进/线程执行。