7.python之线程
什么是线程
线程是应用程序中工作的最小单元,或者称之为微进程.它是进程的实际运作单位,一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
threading.currentThread(): 返回当前的线程变量。 threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。 threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。 除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法: run(): 用以表示线程活动的方法。 start():启动线程活动。 join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。 setDaemon(True):守护主线程,跟随主线程退(必须要放在start()上方) isAlive(): 返回线程是否活动的。 getName(): 返回线程名。 setName(): 设置线程名。
开启线程的两种方式
from threading import Thread def f1(n): print("%s号线程"%n) def f2(n): print("%s号线程"%n) if __name__ == '__main__': p1 = Thread(target=f1,args=(1,)) p2 = Thread(target=f1, args=(2,)) p1.start() p2.start() print("主线程")
from threading import Thread class Mythread(Thread): def __init__(self,name): super(Mythread, self).__init__() self.name = name def run(self): print("%s号线程"%self.name) if __name__ == '__main__': p1 = Mythread("alex") p1.start() print("主线程")
查看线程的进程
import os from threading import Thread def f1(n): print("1号",os.getpid()) print('%s号线程任务'%n) def f2(n): print('2号',os.getpid()) print('%s号线程任务'%n) if __name__ == '__main__': t1 = Thread(target=f1,args=(1,)) t2 = Thread(target=f2,args=(2,)) t1.start() t2.start() print('主线程',os.getpid()) print('主线程')
验证线程数据共享
import time from threading import Thread num =100 def f1(): time.sleep(3) global num num = 3 print('子线程num',num) if __name__ == '__main__': t = Thread(target=f1) t.start() t.join() print("主线程中的num",num)
线程与进程的效率对比
# -*- coding:utf-8 -*- import time from threading import Thread from multiprocessing import Process def f1(): n = 10 for i in range(100): n+=i if __name__ == '__main__': t_s_time = time.time() t_list = [] for i in range(20): t = Thread(target= f1,) t.start() t_list.append(t) [tt.join() for tt in t_list] t_e_time = time.time() t_dir_time = t_e_time - t_s_time p_s_time = time.time() p_list = [] for i in range(20): p = Process(target=f1,) p.start() p_list.append(p) [pp.join() for pp in p_list] p_e_time = time.time() p_dir_time = p_e_time - p_s_time print("多线程执行时间:",t_dir_time) print("多进程执行时间:",p_dir_time)
守护线程
守护线程会等待主程序运行完毕后被销毁
运行完毕并非运行终止
import time from threading import Thread from multiprocessing import Process # 守护进程:主进程代码执行运行结束,守护进程随之结束 #守护线程:守护线程会等待所有非守护线程运行结束才结束 def f1(): time.sleep(2) print('1号进程') def f2(): time.sleep(3) print('2号进程') if __name__ == '__main__': t1 = Thread(target=f1,) t2 = Thread(target=f2,) t1.daemon = True t2.daemon = True t1.start() t2.start() print('主线程') # if __name__ == '__main__': # p1 = Process(target=f1,) # p2 = Process(target=f2,) # p1.daemon = True # p2.daemon = True # p1.start() # p2.start() # print("主进程")
GIL锁
GIL本质是一把互斥锁
# -*- coding:utf-8 -*- import time from threading import Lock ,Thread num =100 def f1(loc): loc.acquire() global num tmp = num tmp -= 1 time.sleep(0.001) num = tmp loc.release() if __name__ == '__main__': t_loc = Lock() t_list = [] for i in range(10): t = Thread(target=f1,args=(t_loc,)) t.start() t_list.append(t) [tt.join() for tt in t_list] print("主线程num",num)
from threading import Thread,Lock,RLock import time def f1(locA,locB): locA.acquire() print("f1>>>1号抢到了A锁") time.sleep(1) locB.acquire() print("f1>>>1号抢到了B锁") locB.release() locA.release() def f2(locA,locB): locB.acquire() print("f2>>>2号抢到了B锁") locA.acquire() time.sleep(1) print("f2>>>2号抢到了A锁") locA.release() locB.release() if __name__ == '__main__': locA = Lock() locB = Lock() t1 = Thread(target=f1,args=(locA,locB)) t2 = Thread(target=f2,args=(locA,locB)) t1.start() t2.start()
# -*- coding:utf-8 -*- from threading import Thread,Lock,RLock import time def f1(locA,locB): locA.acquire() print("f1>>>1号抢到了A锁") time.sleep(1) locB.acquire() print("f1>>>1号抢到了B锁") locB.release() locA.release() def f2(locA,locB): locB.acquire() print("f2>>>2号抢到了B锁") locA.acquire() time.sleep(1) print("f2>>>2号抢到了A锁") locA.release() locB.release() if __name__ == '__main__': locA = locB = RLock() t1 = Thread(target=f1,args=(locA,locB)) t2 = Thread(target=f2,args=(locA,locB)) t1.start() t2.start()
信号量Semaphore
import time,os from threading import Thread,Semaphore def func(): sm.acquire() print("get sm") time.sleep(1) sm.release() if __name__ == '__main__': sm = Semaphore(os.cpu_count()) for i in range(23): t = Thread(target=func) t.start()
Event
from threading import Event e = Event() #初始状态False print(e.is_set()) print('开始等待') e.set() #将事件对象的状态改为True # e.clear() #将事件对象的状态改为false e.wait() #当e对象的状态为False的时候会在这个地方阻塞,改为true之后就直接往下执行 print('结束')
线程的其他方法
Threading.current_thread() #当前线程对象 current_thread().getName() #获取线程名 current_thread().ident #获取线程id Threading.Enumerate() #当前正在运行的线程对象的一个列表 Threading.active_count() #当前正在运行的线程数量
# -*- coding:utf-8 -*- import threading import time from threading import Thread,current_thread def f1(n): time.sleep(1) print("子线程名称",current_thread().getName())#子线程名称 Thread-1 print("%s号线程任务"%n)#1号线程任务 if __name__ == '__main__': t1 = Thread(target=f1,args=(1,)) t1.start() print("主线程名称",current_thread().getName())#主线程名称 MainThread print("主线程Id",current_thread().ident)#主线程Id 12184 print(current_thread())#<_MainThread(MainThread, started 12184)> print(threading.enumerate())#[<_MainThread(MainThread, started 12184)>, <Thread(Thread-1, started 12172)>] print(threading.active_count())#2
线程队列
先进先出队列:queue.Queue(5) 先进后出\后进先出队列:queue.LifoQueue(5) 优先级队列:queue.priorityQueue(5) put的数据是一个元组,元组的第一个参数是优先级数字,数字越小优先级越高,越先被get到被取出来, 第二个参数是put进去的值,如果说优先级相同,那么值别忘了应该是相同的数据类型,字典不行
# -*- coding:utf-8 -*- import queue # 一:先进先出队列 q = queue.Queue(3) q.put(1) q.put(2) q.put(3) print("当前队列的内容长度",q.qsize()) print('查看队列是否满了',q.full()) try: q.put_nowait(4) except Exception: print("队列满了") print(q.get()) print(q.get()) print(q.get()) print("查看队列是否为空",q.empty()) try: q.get_nowait() except Exception: print("队列为空") #队列先进后出 # q = queue.LifoQueue(3) # q.put(1) # q.put(2) # q.put(3) # # print(q.get()) # print(q.get()) # print(q.get()) #优先级队列 # q = queue.PriorityQueue(5) # q.put((4,"alex")) # q.put((2,'zalex'))#如果优先级数字相同,如果数据类型不同会报错 # q.put((2,{'k':666})) # q.put((5,(2,3))) # q.put((1,(1,2))) # q.put((-10,(1,2))) # # print(q.get()) # print(q.get()) # print(q.get()) # print(q.get()) # print(q.get()) # print(q.get()) # # q.put((2,(2,3))) #优先级相同会比较第二个参数在ascii的位置,如果数据类型不同会报错 # q.put((2,(1,3))) # print(q.get()) # print(q.get())
线程池
p.map(f1,可迭代的对象) #异步执行 res.result() #和get方法一样,如果没有结果,会等待,阻塞程序 shutdown() #close+join,锁定线程池,等待线程池中所有已经提交的任务全部执行完毕
# -*- coding:utf-8 -*- from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor from threading import current_thread import time def f1(n,s): time.sleep(1) # print("%s号子线程"%current_thread().ident) # print(n,s) return n+s if __name__ == '__main__': tp = ThreadPoolExecutor(4) # tp = ProcessPoolExecutor(4) # s = tp.map(f1,range(5)) #异步提交任务,参数同样是任务名称,可迭代对象 res_list = [] for i in range(10): res = tp.submit(f1,i,1) #submit是给线程池异步提交任务, print(res) res_list.append(res) tp.shutdown()#主线程等待所有提交给线程池的任务,全部执行完毕 close + join for r in res_list: print(r.result()) print('主线程结束')
线程回调函数
import time from threading import current_thread from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor def f1(n,s): return n+s def f2(n): print('回调函数>>>',n.result()) if __name__ == '__main__': tp = ThreadPoolExecutor(4) res = tp.submit(f1,11,12).add_done_callback(f2)