基本使用
#!/usr/bin/env python # -*- coding: utf-8 -*- ''' 一个应用程序,可以有多进程和多线程 默认情况下的程序都是单进程、单线程的 多进程、多线程目的是为了提高并发 python中:由于有GIL锁 多线程:适用于主要进行IO操作的程序 多进程:适用于主要进行CPU运算的程序 ''' import threading import time def f(arg): time.sleep(5) print(arg) #创建一个线程 t1 = threading.Thread(target=f,args=(123,)) #target,表示子线程要执行的函数 args,表示函数的参数 #默认情况下主线程执行完毕后,如果子线程还没有执行完,主线程会等待子线程执行完成后才终止程序 #如果子线程创建后,设置了setDaemon(True),则主线程执行完毕后直接终止程序,不管子线程是否执行完成 ---默认是False t1.setDaemon(True) #启动线程(等待CPU调度,当cpu开始执行时,执行的是t1对象的run方法) t1.start() #默认情况下主线程创建了子线程后是不会等子线程执行完成的,而是直接往下执行 #如果子线程使用了join方法,则主线程执行到这里时,会一直等待子线程执行完成,才继续向下执行 # t1.join() #jion方法还可以加参数,表示主线程执行到这里时最多等多长时间,如果子线程在该时间内执行完成, # 主线程就继续向下执行,如果到了该时间后子线程还没执行完成,主线程也不再等待,继续向下执行 #t1.join(2) #主线程执行到这里,最多等2秒,2秒内子线程执行完成,则主线程立即向下执行;如果2秒后子线程还没执行完成,则主线程不再等待,继续向下执行 print('end')
队列
#!/usr/bin/env python # -*- coding: utf-8 -*- ''' 对列都是在内存中创建的,进程退出,则对列就没有了 一般队列:先进先出 ''' ''' import queue #创建一个队列 # q = queue.Queue() q = queue.Queue(2) #对列加参数,表示对列最多存放2个数据 print(q.empty()) #判断对列是否为空,对列为空则返回True #向对列中存放数据 q.put(11) q.put(22) print(q.full()) #判断对列是否已满,对列已满则返回True # q.put(33,block=False) #对列最多存放2个数据,第3个存不进去,默认情况是存不进去就一直阻塞等待,可以设置block=False:存不进去,就不等待直接报错 # q.put(33,timeout=2) #数据存不进去也可以设置超时时间,过了超时时间之后还是没存进去就报错 print(q.qsize()) #查看对列中有多少个数据 #从队列中取出数据-----顺序:先进先出 print(q.get()) print(q.get()) # print(q.get(block=False)) #对列中已经没有数据可取,默认情况是阻塞等待,可以设置block=False:取不出数据就报错 # print(q.get(timeout=2)) #也可以设置超时时间,过了超时时间还没取到数据,就报错 ''' #join和task_done一般是一起使用的: # 对列中的每个元素都被认为需要一个task来对其进行操作 # 对列中每个元素的task完成的标志是task完成后调用task_done,告诉对列该元素的task已经完成 # 当使用了join之后,表示需要对列中的每个元素的task都被完成后,程序才能结束,不然就一直阻塞 import queue q = queue.Queue(2) q.put(111) q.put(222) # print(q.get()) q.task_done() #对列每取出一个数据,就执行一下tashk_done函数,告诉对列这个取出任务已经完成 # print(q.get()) q.task_done() q.join() #队列中还有数据,表示对列任务没有完成,就会一直阻塞,直到对列任务完成 # 如果执行get获取了数据,但没有执行task_done,则认为任务没有完成,还是会一直阻塞
#!/usr/bin/env python # -*- coding: utf-8 -*- ''' 除了一般对列,还有一些其他对列: 后进先出对列:后放进的数据先被取出 优先级对列:优先级高的数据先被取出 双向对列:对列两端都能进行存取 ''' import queue #后进先出对列 q1 = queue.LifoQueue() q1.put(123) q1.put(456) print(q1.get()) #优先级对列 q2 = queue.PriorityQueue() q2.put((4,'eric')) q2.put((0,'alex')) #存数据的时候,放的是一个元组:第一个元素表示优先级(0优先级最高),第二个元素才是真正的数据 q2.put((0,'alex1')) #优先级相同的情况下,哪个数据先存放,就先取哪个数据 q2.put((1,'maco')) print(q2.get()) #双向对列 q3 = queue.deque() q3.append(123) #对列后面添加一条数据 q3.append(333) q3.appendleft(456) #对列左边添加一条数据 #上面添加数据完成后,顺序为456、123、333 print(q3.pop()) #从对列后面取出一个数据-----取出333-----对列变为:456、123 print(q3.popleft()) #从对列左边取出一个数据-----取出456----对列变为:123
线程锁
#!/usr/bin/env python # -*- coding: utf-8 -*- ''' 多个线程同时对一个数据进行操作,可能会导致其结果错误,这时就需要用到线程锁 线程锁:同时只允许一个线程更改数据。----线程对共用的数据执行操作时,先对该数据上锁, 不让其他线程操作,等该线程操作完成后,再对数据进行解锁,这时其他线程才能对数据进行操作 ''' import threading import time NUM = 10 def func(lock): global NUM lock.acquire() #要操作NUM,先对其进行上锁 NUM -= 1 time.sleep(1) print(NUM) lock.release() #操作完成,解锁 #定义一把线程锁 # lock = threading.Lock() #该类型的锁只支持一层锁,不支持锁中嵌套锁 lock = threading.RLock() #另一种类型的锁,该类型的锁支持多层嵌套------通常使用该类型的锁 for i in range(10): t = threading.Thread(target=func,args=(lock,)) t.start()
#!/usr/bin/env python # -*- coding: utf-8 -*- ''' 线程锁:同一时刻只允许一个线程对数据进行更改 信号量:同一时刻允许一定数量的线程对数据进行更改-------信号量也是一种锁 事件(event):对所有进程要么全部阻塞,要么全部放行 ''' ''' #信号量 import threading import time NUM = 10 def func(lock,i): global NUM lock.acquire() #要操作NUM,先对其进行上锁 NUM -= 1 time.sleep(1) print('NUM:%s 线程:%s'%(NUM,i)) lock.release() #操作完成,解锁 #定义一个信号量 lock = threading.Semaphore(5) #同一时刻允许5个线程操作数据 for i in range(20): t = threading.Thread(target=func,args=(lock,i)) t.start() ''' #事件(event)机制:全局定义了一个Flag,如果Flag=False,则程序执行wait方法时就会阻塞,如果Flag=True,则wait方法就不再阻塞 #event设置Flag状态的方法:阻塞---event.clear()---Flag=False 不阻塞--event.set()---Flag=True import threading def func(event,i): print(i) event.wait() #检测事件状态(是否进行阻塞)---默认为阻塞 print(i+100) if __name__ == '__main__': event = threading.Event() #创建一个事件对象 for i in range(10): t = threading.Thread(target=func,args=(event,i)) t.start() event.clear() #表示event.wait()处于阻塞状态 inp = input('>>>') if inp == '1': event.set() #表示event.wait()处于不阻塞状态
#!/usr/bin/env python # -*- coding: utf-8 -*- ''' 条件:使得线程等待,只有满足条件才放行n个进程 定时器:指定n秒后执行某操作 ''' ''' #条件第一种使用方式 import threading def func(con,n): #阻塞线程(acquire和wait是一起使用的) con.acquire() con.wait() print('run the thread %s'%n) con.release() if __name__ == '__main__': con = threading.Condition() #创建一个条件对象 for i in range(10): t = threading.Thread(target=func,args=(con,i)) t.start() while True: inp = input('>>>') if inp == 'q': #输入q,退出进程 break #下面是固定搭配 con.acquire() con.notify(int(inp)) #参数为整数,参数是几,就放行几个进程 con.release() ''' ''' #条件第二种使用方式 import threading def f(): ret = False inp = input('>>>') if inp == 'true': ret = True else: ret = False return ret def func(con,n): print(n) #阻塞线程(acquire和wait是一起使用的) con.acquire() con.wait_for(f) #判断参数的真假(f的返回值),如果为True,则不再阻塞,否则继续阻塞,直到参数为True print(n+100) con.release() if __name__ == '__main__': con = threading.Condition() #创建一个条件对象 for i in range(10): t = threading.Thread(target=func,args=(con,i)) t.start() ''' from threading import Timer def hello(): print('Hello World!') t = Timer(5,hello) #设置一个定时器,指定5秒后执行hello函数 t.start()
线程池
#!/usr/bin/env python # -*- coding: utf-8 -*- ''' 线程池: 需求: 线程池是一个容器,可设置最大个数-----对列 从线程池中获取线程,取一个少一个 线程池中没有线程了,就等待 任务执行完毕,交还线程 ''' import queue import threading import time class ThreadPool: """ 自定义线程池 """ def __init__(self,maxsize=5): self.maxsize = maxsize # 线程最大数 self._q = queue.Queue(maxsize) # 创建一个队列用来存放线程 # 初始化线程池,存放最大线程数的threading.Thread类 for i in range(maxsize): self._q.put(threading.Thread) def get_thread(self): """ 从线程池中取线程,线程池中没有线程了就等待 :return: """ return self._q.get() def add_thread(self): """ 任务执行完毕,交还线程,向线程池中添加新的threading.Thread类 :return: """ self._q.put(threading.Thread) def task(args, p): print(args) time.sleep(1) p.add_thread() #任务执行完毕,交还线程 if __name__ == '__main__': pool = ThreadPool(5) # 创建一个线程池对象 for i in range(100): t = pool.get_thread() # 获取一个线程类 obj = t(target=task, args=(i,pool)) # 创建一个线程对象 obj.start() # 启动线程
#!/usr/bin/env python # -*- coding: utf-8 -*- """ http://www.cnblogs.com/wupeiqi/articles/4839959.html """ import queue import threading import contextlib import time StopEvent = object() # 线程停止标志位 class ThreadPool(object): def __init__(self, max_num, max_task_num=None): if max_task_num: self.q = queue.Queue(max_task_num) else: self.q = queue.Queue() # 创建对列,存放任务 self.max_num = max_num self.cancel = False self.terminal = False self.generate_list = [] # 正在执行的线程 self.free_list = [] # 空闲线程 def run(self, func, args, callback=None): """ 线程池执行一个任务 :param func: 任务函数 :param args: 任务函数所需参数 :param callback: 任务执行失败或成功后执行的回调函数,回调函数有两个参数1、任务函数执行状态;2、任务函数返回值(默认为None,即:不执行回调函数) :return: 如果线程池已经终止,则返回True否则None """ if self.cancel: return if len(self.free_list) == 0 and len(self.generate_list) < self.max_num: # 没有空闲的线程,并且正在执行的线程小于最大线程数 self.generate_thread() # 创建新线程 w = (func, args, callback,) self.q.put(w) # 将任务添加到对列中 def generate_thread(self): """ 创建一个线程 """ t = threading.Thread(target=self.call) t.start() def call(self): """ 循环去获取任务函数并执行任务函数 """ current_thread = threading.currentThread() # 获取当前线程 self.generate_list.append(current_thread) # 将当前线程放入正在执行线程的列表 event = self.q.get() #从对列中取任务 while event != StopEvent: # 任务不为线程停止标志,执行任务 func, arguments, callback = event try: result = func(*arguments) #执行函数 success = True #成功 except Exception as e: success = False #执行失败 result = None if callback is not None: #回调函数存在,执行回调函数,返回线程执行的状态和结果 try: callback(success, result) except Exception as e: pass with self.worker_state(self.free_list, current_thread): if self.terminal: # self.terminal为True,表示任务没有任务了 event = StopEvent else: #还有任务,继续取 event = self.q.get() else: # 任务等于线程停止标志位,线程停止执行 self.generate_list.remove(current_thread) # 从正在执行线程列表中移除当前线程 def close(self): """ 执行完所有的任务后,所有线程停止 """ self.cancel = True full_size = len(self.generate_list) while full_size: self.q.put(StopEvent) full_size -= 1 def terminate(self): """ 无论是否还有任务,终止线程 """ self.terminal = True while self.generate_list: self.q.put(StopEvent) self.q.queue.clear() @contextlib.contextmanager def worker_state(self, state_list, worker_thread): """ 用于记录线程中正在等待的线程数 """ state_list.append(worker_thread) try: yield finally: state_list.remove(worker_thread) # How to use pool = ThreadPool(5) def callback(status, result): # status, execute action status # result, execute action return value pass def action(i): # import random # time.sleep(0.5) print(i) for i in range(30): pool.run(action, (i,), callback) while True: print(len(pool.generate_list), len(pool.free_list)) if len(pool.free_list) == len(pool.generate_list): pool.close() print('END') break time.sleep(1) # pool.terminate()
关注我的公众号,不定期推送资讯
本文来自博客园,作者:链条君,转载请注明原文链接:https://www.cnblogs.com/MacoLee/articles/6125648.html