1.线程基本操作
1.创建线程的方式
#创建线程方法一(最常见)
import threadingdef f1(args):print(args)
t = threading.Thread(target=f1,args=(123,))
t.start() #线程开启,等待cpu调用'''
t.run() 方法:当cpu调度的时候,就执行Thread里边的run方法t.run() #是由cpu替我们调度执行的
'''#创建线程方法二 (通过创建类创建线程) (自定义方式)
import threading
class MyThread(threading.Thread):def __init__(self,func,args): #定义init,就不执行父类的方法了,执行自己的self.func = funcself.args = argssuper(MyThread,self).__init__()def run(self):self.func(self.args)def f2(arg):print(arg)
obj = MyThread(f2,123) #func = f2 args=123
obj.start()
2.线程锁(同时只允许一个线程进入取值。)
线程锁分类:1.l.acquire()l.release()lock = threading.Lock() #只能锁一次2.l.acquire()l.release()lock = threadingRLock() #可以递归锁,可以锁多层,可以嵌套。 (常用)例子:
当有一个数字10,如果同时10个线程去减1,
那么就会产生脏数据,输出结果都输出为0。#例1
import threading
import time
NUM = 10def func(l):global NUMNUM -= 1time.sleep(2) #会产生脏数据,造成输出都是0print(NUM)
lock = threading.Lock() #只能锁一次
for i in range(10):t = threading.Thread(target=func,args=(lock,))t.start()#解决此问题就是加锁,同时只允许一个线程进入取值。;(单层锁)
#例2
import threading
import time
NUM = 10def func(l):global NUMl.acquire() #上锁 使同一时刻只有一个进程使用NUM -= 1time.sleep(2) #会产生脏数据,造成输出都是0print(NUM)l.release() #开锁
lock = threading.Lock() #只能锁一次
for i in range(10):t = threading.Thread(target=func,args=(lock,))t.start()#例3 多层锁
import threading
import time
NUM = 10def func(l):global NUM#上锁 #使同一时刻只有一个进程使用l.acquire()NUM -= 1l.acquire() #多层锁time.sleep(2) #会产生脏数据,造成输出都是0l.release() #多层锁print(NUM)l.release() #开锁
#lock = threading.Lock() #只能锁一次
lock = threading.RLock() #可以递归锁,可以锁多层,可以嵌套。
for i in range(10):t = threading.Thread(target=func,args=(lock,))t.start()
3.信号量以及事件
信号量(semaphore)(同时允许一定数量的线程更改数据)#例1 信号量(semaphore)(同时允许一定数量的线程更改数据)
import threading
import time
NUM = 10def func(i,l):global NUM#上锁 #使同一时刻只有一个进程使用lock.acquire() #一次放5个出去NUM -= 1time.sleep(2) #会产生脏数据,造成输出都是0print(NUM,i)#开锁lock.release()
lock = threading.BoundedSemaphore(5)
for i in range(30):t = threading.Thread(target=func,args=(i,lock,))t.start()#例2 事件(event)(事件用于主线程控制其他线程的执行,相当于红绿灯。主要有三个方法:set、wait、clear)
#批量将所有线程挡住,改一个标识,全部放走
#内部就是维护了一个状态,默认是False,改成True就能走了 。
#输出结果顺序不一样,是因为线程调度事件不一样
import threadingdef func(i,e):print(i)e.wait() #表示它在这等待;检测是什么灯,如果是红灯就停;print(i+100)
event = threading.Event()
for i in range(10):t = threading.Thread(target=func,args=(i,event,))t.start()
#==========
event.clear() #主动设置成红灯就是False,默认是False
inp = input(">>")
if inp == "1": #当输入1的时候就继续event.set() #把上边的红灯设置成绿灯,将Flag设置为True
4.条件以及定时器
条件Condition (使得线程等待,只有满足某条件时,才释放n个线程)#例1: 当输入数字等于几时,那么久释放几个线程过去。
import threadingdef run(n):con.acquire() #配合下边wait使用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=run, args=(i,))t.start()while True:inp = input('>>>')if inp == 'q':break#以下三行是固定用法con.acquire()con.notify(int(inp))con.release()#当条件满足之后,出去一个,再满足,再出去一个
#例2 当满足条件,输入true,那么就i+100 ,再输入true 下个数再加100
import threading
def condition():ret = Falser = input(">>>>")if r == 'true':ret = Trueelse:ret = Falsereturn retdef func(i,con):print(i)con.acquire() #配合下边wait使用con.wait_for(condition) #在这里等着了print(i+100)con.release()c = threading.Condition()
for i in range(10):t = threading.Thread(target=func,args=(i,c,))t.start()#定时器 Timer (定时器,指定n秒后执行某操作)
#例3
#1秒钟之后执行某函数
#应用到写客户端、监控的时候。from threading import Timerdef hello():print("hello world")t = Timer(1,hello) #1秒钟之后执行
t.start()
2.队列的使用(Python中队列是线程间最常用的交换数据的形式)
1.queue队列基本特点:先进先出方法:put 放数据,是否阻塞,阻塞时的超时时间get 取数据,默认阻塞,是否阻塞,阻塞时的超时时间q.empty 检查队列是否为空,为空返回True,否则Falseq.full 判对是否满了q.qsize 队列里边有几个元素;当前真实个数q.maxsize 元素最大支持的个数q.join 如果队列任务没有完成,还在等待。q.taskdone 每一次取完数据的时候执行q.task_done(),告诉我执行完了,系统做一个计数。表示我取完数据了join,task_done 阻塞进程,当队列中任务执行完毕之后,不再阻塞。
2.其他队列:1、后进先出queue.LifoQueue2、优先级队列 (放数据的时候加上权重值;内容包括:数据+权重)queue.PriorityQueue3、双向队列 (两边存、两边取)queue.dequeimport queue #导入队列模块q = queue.Queue(10) #创建一个队列;参数10代表最多接收10个数据。放不进去就等着或者报错
q.put(11,timeout=2) #放数据;timeout=2 代表等待2秒,如果还没有位置就报错;有位置就加进去
q.put(22,block=False) #默认block是阻塞等待,只要没有位置就等待;如果改成True,就不等待,直接报错
q.put(33)
print(q.qsize()) #显示当前多少数据
print(q.get(block=False)) #取数据;默认是阻塞,默认情况下没有数据的时候就一直等待,
print(q.empty()) #检查队列是否为空,为空返回True,否则False
#输出311Falseq = queue.Queue(5)
q.put(33)
q.put(44)
print(q.get())
print(q.task_done())
print(q.get())
print(q.task_done())
#输出:33None44None
#每一次取完数据的时候执行q.task_done(),告诉我执行完了,系统做一个计数。表示我取完数据了
#q.join() #如果队列任务没有完成,还在等待。#queue.LifoQueue 特点:后进先出
q = queue.LifoQueue()
q.put(123)
q.put(456)
print(q.get()) #456是后进去的,先取出来
#输出:456#queue.PriorityQueue 特点:优先级队列
q = queue.PriorityQueue()
q.put((1,'aaa'))
q.put((2,'bbb'))
print(q.get()) #按照优先级取数据,如果优先级相同,谁先放,先取谁
#输出:(1, 'aaa')#queue.deque 特点:双向队列(两边都可以取数据,都可以放数据)
q =queue.deque()
q.append(123)
q.append(456)
q.appendleft(333) #左边放数据
print(q.pop()) #取数据,默认取最右边的
print(q.popleft()) #左边取数据
#输出:456333
3.自定义线程池
|