人生苦短之我用Python篇(线程/进程、threading模块:全局解释器锁gil/信号量/Event、)
线程: 有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。是一串指令的集合。
线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。
在单个程序中同时运行多个线程完成不同的工作,称为多线程。
进程: qq 要以一个整体的形式暴露给操作系统管理,里面包含对各种资源的调用,内存的管理,网络接口的调用等。。。
对各种资源管理的集合 就可以成为进程。
进程 要操作cpu , 必须要先创建一个线程,
all the threads in a process have the same view of the memory
所有在同一个进程里的线程是共享同一块内存空间的
进程与线程的区别?
Threads share the address space of the process that created it; processes have their own address space.
线程共享内存空间,进程的内存是独立的
Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.
Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.
同一个进程的线程之间可以直接交流,两个进程想通信,必须通过一个中间代理来实现
New threads are easily created; new processes require duplication of the parent process.
创建新线程很简单, 创建新进程需要对其父进程进行一次克隆
Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.
一个线程可以控制和操作同一进程里的其他线程,但是进程只能操作子进程
Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.
threading模块
import time import threading def run(n): print('task.....',n) time.sleep(2) # run("t1") # run("t2")
#普通写法
t1 = threading.Thread(target=run,args=("t1",)) t2 = threading.Thread(target=run,args=("t2",)) t1.start() t2.start()
import time import threading #类写法 class MyThread(threading.Thread): def __init__(self,n,sleep_time): super(MyThread, self).__init__() self.n = n self.sleep_time = sleep_time def run(self): print("task", self.n) time.sleep(self.sleep_time) print("task done") t1 = MyThread("t1",2) t2 = MyThread("t2",4) t1.start() t2.start()
import threading import time def run(n): print("task ",n ) time.sleep(2) print("task done",n) start_time = time.time() t_objs = [] #存线程实例 for i in range(50): t = threading.Thread(target=run,args=("t-%s" %i ,)) t.start() t_objs.append(t) #为了不阻塞后面线程的启动,不在这里join,先放到一个列表里 for t in t_objs: #循环线程实例列表,等待所有线程执行完毕 t.join() print(t_objs) print("----------all threads has finished...") print("cost:",time.time() - start_time)
Daemon:守护进程,即主进程一结束,守护进程也就结束
import threading import time def run(n): print("task ",n ) time.sleep(2) print("task done",n,threading.current_thread()) start_time = time.time() t_objs = [] #存线程实例 for i in range(50): t = threading.Thread(target=run,args=("t-%s" %i ,)) t.setDaemon(True) #把当前线程设置为守护线程 t.start() t_objs.append(t) #为了不阻塞后面线程的启动,不在这里join,先放到一个列表里 # for t in t_objs: #循环线程实例列表,等待所有线程执行完毕 # t.join() # time.sleep(2) print("----------all threads has finished...",threading.current_thread(),threading.active_count()) print("cost:",time.time() - start_time)
全局锁
import threading import time def run(n): lock.acquire()#获得锁,除非释放掉锁,否则其他线程就不能再次获得,2.7中试,3.0以后不需要了 global num num +=1 # time.sleep(1) lock.release()#释放锁,其他线程可以获得了 lock = threading.Lock() num = 0 t_objs = [] #存线程实例 for i in range(50): t = threading.Thread(target=run,args=("t-%s" %i ,)) t.start() t_objs.append(t) #为了不阻塞后面线程的启动,不在这里join,先放到一个列表里 for t in t_objs: #循环线程实例列表,等待所有线程执行完毕 t.join() print("----------all threads has finished...",threading.current_thread(),threading.active_count()) print("num:",num)
信号量:即同时可以获得多个锁
import threading import time def run(n): semaphore.acquire()#信号量获取 time.sleep(1) print("run the thread :%s\n" %n) semaphore.release()#信号量释放 if __name__ == "__main__": semaphore = threading.BoundedSemaphore(5) #设置信号量,即绑定信号量可以同时拥有的锁的数量 for i in range(22): t = threading.Thread(target = run,args = (i,)) t.start() while threading.active_count() !=1 :#当前活跃的线程数 pass else: print("______-all threads done______")
Event:
event = threading.Event()#生成event对象
event.set()#设置event标志位
event.clear()#清除event标志位
event.is_set():#判断event是否设置了标志位
红绿灯例子:
import time import threading event = threading.Event()#生成event对象 def lighter(): event.set()#设置event标志位 count = 0 while True: if count >5 and count <10: event.clear()#清除event标志位 print("\033[41;1m红灯亮....\033[0m") elif count > 10: event.set() print("\033[42;1m绿灯亮了....\033[0m") count = 0 else: print("\033[42;1m绿灯亮着\033[0m") time.sleep(1) count +=1 def car(n): while True: if event.is_set():#判断event是否设置了标志位 print('\033[34;2m[%s] running..... \033[0m'%n) time.sleep(0.5) else: print('[%s] stoping.....'%n) event.wait() print('路灯亮了[%s]开跑'%n) light = threading.Thread(target=lighter,) light.start() car1 = threading.Thread(target=car,args=('宝马',)) car1.start() car2 = threading.Thread(target=car,args=('大奔驰',)) car2.start() car3 = threading.Thread(target=car,args=('玛莎拉蒂',)) car3.start()
多进程:
和线程用法基本一致,我threading.Thread换成multiprocessing.Process
import time,threading import multiprocessing def thread_run(): print(threading.get_ident()) def run(name): time.sleep(2) print("hellp",name) t = threading.Thread(target=thread_run,) t.start() if __name__ =="__main__": for i in range (10): p = multiprocessing.Process(target=run,args=("bob %s"%i,))#与线程用法基本机制 p.start()
数据在不同进程间进行交换
from multiprocessing import Process,Queue def f(qq): qq.put([42,None,156161]) if __name__ =="__main__": q =Queue()#可以在不同进程间交互使用 p = Process(target=f,args=(q,))#把q作为参数传入 p.start() print(q.get())#父进程可以得到子进程中修改过的数据 p.join()
进程池
Note: from multiprocessing import Process, Pool,freeze_support
pool = Pool(processes=5) #允许进程池同时放入5个进程
pool.apply_async(func=Foo, args=(i,), callback=Bar) #callback=回调,父进程操作
#pool.apply(func=Foo, args=(i,)) #串行
#pool.apply_async(func=Foo, args=(i,)) #并行
from multiprocessing import Process, Pool,freeze_support import time import os def Foo(i): time.sleep(2) print("in process",os.getpid()) return i + 100 def Bar(arg): print('-->exec done:', arg,os.getpid()) if __name__ == '__main__':#window必须加这一句 #freeze_support() pool = Pool(processes=5) #允许进程池同时放入5个进程 print("主进程",os.getpid()) for i in range(10): pool.apply_async(func=Foo, args=(i,), callback=Bar) #callback=回调 #pool.apply(func=Foo, args=(i,)) #串行 #pool.apply_async(func=Foo, args=(i,)) #并行 print('end') pool.close() pool.join() #进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。.join()
进程锁:变串行了
from multiprocessing import Process, Lock def f(l, i): #l.acquire() print('hello world', i) #l.release() if __name__ == '__main__': lock = Lock() for num in range(100): Process(target=f, args=(lock, num)).start()
Manager:进程间交换数据
from multiprocessing import Process, Manager import os def f(d, l): d[os.getpid()] =os.getpid() l.append(os.getpid()) print(l) if __name__ == '__main__': with Manager() as manager: d = manager.dict() #{} #生成一个字典,可在多个进程间共享和传递 l = manager.list(range(5))#生成一个列表,可在多个进程间共享和传递 p_list = [] for i in range(10): p = Process(target=f, args=(d, l)) p.start() p_list.append(p) for res in p_list: #等待结果 res.join() print(d) print(l)
Pipe:生成两个可以交互数据的进程
parent_conn, child_conn = Pipe()#生成两个可以交换数据的进程
from multiprocessing import Process, Pipe def f(conn): conn.send([42, None, 'hello from child']) conn.send([42, None, 'hello from child2']) print("from parent:",conn.recv()) conn.close() if __name__ == '__main__': parent_conn, child_conn = Pipe()#生成两个可以交换数据的进程 p = Process(target=f, args=(child_conn,)) p.start() print(parent_conn.recv()) # prints "[42, None, 'hello']" print(parent_conn.recv()) # prints "[42, None, 'hello']" parent_conn.send("可好") # prints "[42, None, 'hello']" p.join()
我们的目标是星辰大海。