python多线程详解(二)

线程本地数据(threading.local)

​ 线程本地数据,其实是创建一个全局的类似于字典的数据类型,让所有的线程在访问此字典的时候只能访问自己的数据,将线程之间的数据分隔开,避免冲突

import threading

local = threading.local()


def one():
    local.a = 0
    for i in range(100):
        local.a += 1
    print(local.a)
    return


def two():
    local.a = 0
    for i in range(1000):
        local.a += 2
    print(local.a)
    return


if __name__ == '__main__':
    one = threading.Thread(target=one)
    two = threading.Thread(target=two)
    one.start()
    two.start()


'''
100 
2000
'''

条件对象(Condition)

​ 条件对象本质上也是一把锁,可以是同步锁也可以是递归锁,可以自己传入,也可以自动创建,一般情况下,自动创建即可。条件对象不仅具有锁的功能,还可以实现简单的线程间通信。

把条件对象当做普通的锁来使用:

import threading

con = threading.Condition()
num = 0


class Consumer(threading.Thread):
    def run(self):
        global num
        for i in range(10):
            con.acquire()
            num += 1
            con.release()


class Producer(threading.Thread):
    def run(self):
        global num
        for i in range(10):
            con.acquire()
            num += 1
            con.release()


if __name__ == '__main__':
    for i in range(10):
        consumer = Consumer()
        producer = Producer()
        consumer.start()
        producer.start()
        consumer.join()
        producer.join()
    print(num)

​ 条件对象显然不是直接当成锁来使用的,条件对象的关键在于实现了线程间的简单通信

简单的生产者消费者模型:

import threading

con = threading.Condition()
num = 0


class Consumer(threading.Thread):
    def run(self):
        global num
        con.acquire()
        con.wait()
        num -= 1
        print(f'{self.ident} -1')
        con.notify()
        con.release()


class Producer(threading.Thread):
    def run(self):
        global num
        con.acquire()
        num += 1
        print(f'{self.ident} +1')
        con.notify()
        con.wait()
        con.release()


if __name__ == '__main__':
    for i in range(10):
        consumer = Consumer()
        producer = Producer()
        consumer.start()
        producer.start()
        consumer.join()
        producer.join()

'''
11624 +1
3124 -1
10128 +1
11440 -1
7328 +1
11876 -1
5272 +1
12216 -1
6612 +1
12280 -1
10024 +1
1428 -1
10452 +1
12016 -1
292 +1
12112 -1
9420 +1
6296 -1
6332 +1
2840 -1
'''

​ 创建20个线程,10个生产者,10个消费者。一个生产者对num的值+1,一个消费者对num的值-1。

方法描述
wait()阻塞调用此方法的线程。
notify(n=1)通知阻塞了的线程,继续运行。n表示最多通知多少个线程。此方法并不会释放锁,释放锁还是需要release()。
notify_all()唤醒所有等待的线程
acquire()获得锁
release()释放锁

信号量对象(Semaphore)

​ 信号量的本质也是锁,信号量对象内部维护着一个计数器,每当调用acquire()方法,计数器的值就会-1,每当调用release()方法,计数器的值就会+1。特别之处在于,计数器的不能为负数,当某个线程调用acquire()方法,发现计数器的值为0,就会阻塞,默认值为1。计数器初始值的作用就是同一时刻允许的最大线程运行数。

用信号量来实现生产者消费者模型:

import threading
import time

# 设置初始的计数器值
semaphore = threading.Semaphore(value=5)
num = 0


class Consumer(threading.Thread):
    def run(self):
        global num
        semaphore.acquire()
        num -= 1
        print(f'{self.ident} -1')
        semaphore.release()


class Producer(threading.Thread):
    def run(self):
        global num
        time.sleep(2)
        semaphore.acquire()
        num += 1
        print(f'{self.ident} +1')
        semaphore.release()


if __name__ == '__main__':
    for i in range(10):
        consumer = Consumer()
        producer = Producer()
        consumer.start()
        producer.start()
        consumer.join()
        producer.join()

事件对象(Event)

​ 这是线程之间通信的最简单机制之一:一个线程发出事件信号,而其他线程等待该信号。一个事件对象管理一个内部标识,调用 set()方法可将其设置为 true ,调用 clear()方法可将其设置为 false ,调用 wait() 方法将进入阻塞直到标识为 true 。

import threading
import time

event = threading.Event()


class Task(threading.Thread):
    def run(self):
        event.wait()
        print(f'{self.ident}  收到通知')


if __name__ == '__main__':
    for i in range(5):
        task = Task()
        task.start()
    time.sleep(5)
    event.set()
    
    
"""
10680  收到通知
11076  收到通知
600  收到通知
11672  收到通知
8912  收到通知
"""

​ 主线程将内部的标识符改为False,调用了wait()方法的线程就会停止阻塞,开始执行任务。

栅栏对象(Barrier)

​ 栅栏对象用于实现多个线程间的同步,栅栏对象有内置的wait()方法,调用该方法,会使当前的线程阻塞,但是一旦在所有的线程都调用了wait()方法,则会自动解除阻塞。

import threading

# 实例化栅栏对象,并设置最多同步多少个线程
barrier = threading.Barrier(2)


def one():
    barrier.wait()
    print('one')


def two():
    barrier.wait()
    print('two')


o = threading.Thread(target=one)
t = threading.Thread(target=two)
o.start()
t.start()
o.join()
t.join()

'''
one
two
'''

定时器对象(Timer)

​ 定时器对象就是可定时执行任务,其本质就是一个阻塞一定时长的线程。

import threading


def show():
    print('time out!!!')

timer = threading.Timer(10, show)
timer.start()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值