Python 进程和线程

对于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模块包装了底层的机制,提供了QueuePipes等多种方式来交换数据。

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)

没上锁时,数据冲突

上锁后

原文地址:https://www.cnblogs.com/bfcs/p/10783045.html