python并发编程(五)——线程(二)

线程中的信号量Semaphore

threading模块中Semaphore就是信号量
semaphore本质就是一个内置的计数器
每当调用acquire()时,内置计数器-1
每当调用release()时,内置计数器+1
计数器不能小于0,当计数器为0时,acquire()将阻塞线程直到其他线程调用release()
作用:可以在获取锁的同时限制当前只能有多少个线程对象获取锁
import time
from threading import Semaphore,Thread
def func(sem,a,b):
    sem.acquire()#获取锁
    time.sleep(2)
    print(a+b)
    sem.release()#释放锁

sem = Semaphore(4)#同一时间只能有4个线程对象获取锁,其他线程释放锁后才有获取被释放的锁
for i in range(10):#利用循环开启10个线程
    t = Thread(target=func,args=(sem,i,i+5))
    t.start()

线程中的事件Event

Event就是定义了一个全局的内置标志Flag
Event创建后默认是False
event.wait:当事件的状态为False时,阻塞当前线程
event.set():将事件的状态置为True,并通知阻塞线程恢复运行状态
event.clear():将事件的状态置为False
event.isSet(): 获取事件的标志状态,返回True或False
import time
import random
from threading import Thread,Event
def connect_db(e):
    count = 0
    while count < 3:
        e.wait(0.5)   # 状态为False的时候,休眠0.5s
        if e.is_set() == True:
            print('连接服务器成功')
            break
        else:
            count += 1
            print('第%s次连接失败'%count)
    else:
        raise TimeoutError('服务器连接超时')#主动抛出一个异常

def check_web(e):
    time.sleep(random.randint(0,3))#随机休眠0-3秒
    e.set()#将事件的状态改为True

e = Event()#创建一个事件,默认状态为False
t1 = Thread(target=connect_db,args=(e,))#创建线程
t2 = Thread(target=check_web,args=(e,))
t1.start()#启动线程
t2.start()
#创建2个线程
#线程1判断事件状态,在前三次连接中如果事件状态为True就输出连接数据库成功
#如果三次中状态都为False,第四次直接抛出一个异常
#线程2随机休眠0-3秒后将事件的状态置为True

线程中的Condition

Condition可以控制线程的状态
可以获取锁,释放锁
主要方法
wait(timeout)休眠当前线程
notify(int i)唤醒等待池中x个线程对象
notifyAll()唤醒所有线程
以上方法必须在acquire()和release()之间调用
from threading import Condition
from threading import Thread
import time
def func(con,i):
    con.acquire()
    con.wait() # 等待
    print('在第%s个循环里'%i)
    con.release()
    
    
con = Condition()#创建条件对象
for i in range(10):
    Thread(target=func,args = (con,i)).start()#启动10个子线程
while True:
    con.acquire()
    con.notify(2)  # 每次唤醒2个线程
    con.release()
    time.sleep(1)#休眠1秒
#在子线程中通过条件对象让线程休眠
#在主线程中每次唤醒2个线程对象然后休眠1秒

定时器

from threading import Timer
from threading import Timer
from nt import getpid
import threading
import os
def fun():
    print('定时器',getpid(),os.getpid(),threading.get_ident())
    #获取进程id与当前子线程id——定时器 5128 5128 4456

if __name__ == '__main__':
    t = Timer(2,fun).start()#2秒钟后开启一个子线程调用fun方法
    print(getpid(),os.getpid(),threading.get_ident())
    #获取进程id与当前主线程id——5128 5128 4112

线程中的队列

队列:用于线程间的通信,列表也可以用于线程通信(线程间数据共享),为什么还要队列?
列表的数据共享需要手动加锁来保证数据安全
队列内置了线程安全模块
队列是一种数据结构,特点是元素先进先出
常用方法:
Queue.qsize() 返回队列的大小
Queue.empty() 如果队列为空,返回True
Queue.full() 如果队列满了,返回True
Queue.put(item) 将元素写入队列
Queue.get(item) 从队列获取元素
Queue.join() 实际上意味着等到队列为空,再执行别的操作
import queue
#先进先出的队列
q=queue.Queue()
q.put('1')
q.put('2')
q.put('3')

print(q.get())#1
print(q.get())#2
print(q.get())#3
import queue
#后进先出的队列
q=queue.LifoQueue()
q.put('1')
q.put('2')
q.put('3')

print(q.get())#3
print(q.get())#2
print(q.get())#1
import queue
#优先级队列
q=queue.PriorityQueue()
#put一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高
q.put((20,'a'))
q.put((10,'b'))
q.put((30,'c'))
#按照优先级输出,优先级越高的先输出
print(q.get())#(10, 'b')
print(q.get())#(20, 'a')
print(q.get())#(30, 'c')

线程池

线程的创建和销毁非常销毁资源,为解决这个问题,线程池的概念被提出来了。
预先创建好一个较为优化的数量的线程池,使用线程的时候从线程池中获取,使用完毕将线程放回线程池
submit(fn, *args, **kwargs)异步提交任务
shutdown(wait=True) 相当于进程池的pool.close()+pool.join()操作,等待池内所有任务执行完毕回收完资源后才继续
result(timeout=None)取得线程的返回结果
add_done_callback(fn)回调函数
done()判断某一个线程是否完成
cancle()取消某个任务
import time
from concurrent.futures import ThreadPoolExecutor
def func(n):
    time.sleep(2)
    print(n)
    return n*n

def call_back(m):
    print('结果是 %s'%m.result())

tpool = ThreadPoolExecutor(max_workers=5)   #创建线程池,默认线程数为5
for i in  range(20):
    tpool.submit(func,i).add_done_callback(call_back)
    #开启异步提交,传入返回值调用回调函数,在回调函数中利用result()获取线程的返回值
    #回调函数是在主线程中完成的,不是子线程
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值