对于OS来说,一个任务(如打开word)就是一个进程
有些进程不止同时干一件事,如word可以同时进行打字、拼写检查、打印等事情,进程内的子任务称为线程
多进程
multiprocessing模块 跨平台版本的多进程模块
启动一个子进程并等待其结束
1 #!/usr/bin/python3 2 3 from multiprocessing import Process 4 import os 5 6 #子进程要执行的代码 7 def run_proc(name): 8 print('运行的子进程 %s(%s)' % (name, os.getpid())) 9 10 if __name__ == '__main__': 11 print('父进程 %s' % os.getpid()) 12 p = Process(target = run_proc, args = ('qwer',)) #创建子进程对象 13 print('子进程将要开始运行--------') 14 p.start() 15 p.join() #等待子进程结束后再继续往下运行,通常用于进程间的同步 16 print('子进程结束---------')
子进程只需要调用getpid()就可拿到父进程ID
Pool 启动大量的子进程 用进程池的方式
1 #!/usr/bin/python3 2 3 from multiprocessing import Pool 4 import os,time,random 5 6 def long_time_task(name): 7 print('Run task %s (%s)-----' % (name, os.getpid())) 8 start = time.time() #放回当前时间戳 9 time.sleep(random.random()*3) 10 end = time.time() 11 print('Task %s runs %0.2fs' % (name, (end-start))) 12 13 if __name__ == '__main__': 14 print('父进程 %s' % os.getpid()) 15 p = Pool(4) #设置同时跑四个进程 16 for i in range(5): 17 p.apply_async(long_time_task, args = (i,)) #apply应用程序 asvnc异步化 18 print('等待所有子程序完成------') 19 p.close() 20 p.join() 21 print('所有子程序完成')
调用join()之前必须先调用close()
进程间通信
Process
之间肯定是需要通信的,Python的multiprocessing
模块包装了底层的机制,提供了Queue
、Pipes
等多种方式来交换数据。
以Queue
为例,在父进程中创建两个子进程,一个往Queue
里写数据,一个从Queue
里读数据:
1 #!/usr/bin/python3 2 3 from multiprocessing import Process,Queue 4 import os,time,random 5 6 #写数据 7 def write(q): 8 print('写进程: %s' % os.getpid()) 9 for value in ['A', 'B', 'C']: 10 print('Put %s to queue------' % value) 11 q.put(value) 12 time.sleep(random.random()) 13 14 #读数据 15 def read(q): 16 print('读进程: %s' % os.getpid()) 17 while True: 18 value = q.get(True) 19 print('Get %s from queue------' % value) 20 21 if __name__ == '__main__': 22 #父进程创建Queue,并传给各个子进程 23 q = Queue() 24 pw = Process(target = write, args = (q,)) 25 pr = Process(target = read, args = (q,)) 26 #启动子进程pw,写入 27 pw.start() 28 #启动子进程pr,读取 29 pr.start() 30 #等待pw结束 31 pw.join() 32 #pr进程死循环,无法等待其结束,强行终止 33 pr.terminate()
多线程
启动一个线程就是把一个函数传入并创建Thread(实例),然后start()执行
1 #!/usr/bin/python3 2 3 import time,threading 4 5 #线程要执行的代码 6 def loop(): 7 print('Thread %s is runing----' % threading.current_thread().name) 8 n = 0 9 while n<5: 10 n = n+1 11 print('thread %s>>>%s' % (threading.current_thread().name, n)) 12 time.sleep(1) 13 print('thread %s end' % threading.current_thread().name) 14 15 print('thread %s is runing----' % threading.current_thread().name) 16 t = threading.Thread(target = loop, name = 'LoopThread') 17 t.start() 18 t.join() 19 print('thread %s end' % threading.current_thread().name)
任何进程默认会启动一个线程(主线程),主线程又可以启动新的线程,current_thread()函数返回当前线程的实例,如果不给子线程指定名字,默认Thread-1,Thread-2........
Lock
多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响
多线程中,所有变量都由所有线程共享,为防止修改冲突,需给线程上锁,锁只有一个,同一个时刻最多只有一个线程持有该锁
1 #!/usr/bin/python3 2 3 import time,threading 4 5 balance = 0 #假定这是银行存款 6 7 def change_it(n): #先存后取,结果应该为0 8 global balance 9 balance = balance + n 10 balance = balance - n 11 12 lock = threading.Lock() #创建锁对象 13 14 def run_thread(n): 15 for i in range(100000): 16 lock.acquire() #上锁 17 try: 18 change_it(n) 19 finally: #改完一定要释放锁 20 lock.release() 21 22 t1 = threading.Thread(target = run_thread, args = (5,)) 23 t2 = threading.Thread(target = run_thread, args = (10,)) 24 t1.start() 25 t2.start() 26 t1.join() 27 t2.join() 28 print(balance)
没上锁时,数据冲突
上锁后