Python多线程学习(三)

定时器

定时器用处

程序中,经常用到这种,就是需要固定时间执行的,或者需要每隔一段时间执行的。这里经常用的就是Timer定时器。Thread 类有一个 Timer子类,该子类可用于控制指定函数在特定时间内执行一次。

代码实例
import threading
import time
def run():
    print('定时器启动')
    print(threading.current_thread())    #  显示当前线程的方法
    timer = threading.Timer(5,run)    #  使用定时器,调用run方法,且时间为5秒,每5秒输出一次
    timer.start()


if __name__=='__main__':
    t1 = threading.Timer(5,function=run)   #  使用定时器,调用run方法,且时间为5秒,每5秒输出一次
    t1.start()

    while True:
        time.sleep(5)
        print('主线程')
        

运行结果
在这里插入图片描述

队列

队列的概念

队列是线性的集合,对于队列来说,插入限制在一端(队尾),删除限制在另一端(队头)。队列支持先进先出(FIFO)的协议。

我们在后面会提到一种特殊的队列——优先队列,在优先队列中,具有较高优先级的项会在那些具有较低优先级的项之前弹出,而具有相同优先级的项,则会按照先进先出(FIFO)的顺序弹出。

队列中含有的方法

在这里插入图片描述

代码示例
import queue

q = queue.Queue(maxsize=3)
q.put((1,'你好1'))
q.put((3,'你好3'))

print(q.full())# 判断是否放满了
q.put((2,'你好'))
q.full()
print(q.full())# 判断是否放满了

print(q.get())
print(q.empty())   # 判断是否为空  --fales,只取了1个
print(q.get())

print(q.get())
print(q.empty())   # 判断是否为空  --true,三个都取完了
print(q.qsize())




运行结果
在这里插入图片描述

import queue
import threading
import time

q = queue.Queue(maxsize=10)

# 相当于生产者,生产视频
def put_in():
    count = 1
    while True:
        q.put(f'视频{count}')
        print(f'up主录制了视频{count}')
        count += 1
        time.sleep(1)

# 相当于消费者,霸占视频
def get_out(name):
    while True:
        print(f'{name}霸占了{q.get()}')
        time.sleep(1)


if __name__=='__main__':
    p = threading.Thread(target=put_in)   #  生产者线程
    p.start()
    g = threading.Thread(target=get_out,args=('小潮',))    # 消费者线程
    g.start()
    g = threading.Thread(target=get_out, args=('海皇',))    # 消费者线程
    g.start()

运行结果
在这里插入图片描述

线程池

线程池的作用

由于线程预先被创建并放入线程池中,同时处理完当前任务之后并不销毁而是被安排处理下一个任务,因此能够避免多次创建线程,从而节省线程创建和销毁的开销,能带来更好的性能和系统稳定性。

线程池方法

线程池的基类是 concurrent.futures 模块中的 Executor,Executor 提供了两个子类,即 ThreadPoolExecutor 和 ProcessPoolExecutor,其中 ThreadPoolExecutor 用于创建线程池,而 ProcessPoolExecutor 用于创建进程池。

如果使用线程池/进程池来管理并发编程,那么只要将相应的 task 函数提交给线程池/进程池,剩下的事情就由线程池/进程池来搞定。

Exectuor 提供了如下常用方法:

submit(fn, *args, **kwargs):将 fn 函数提交给线程池。*args 代表传给 fn 函数的参数,*kwargs 代表以关键字参数的形式为 fn 函数传入参数。

map(func, *iterables, timeout=None, chunksize=1):该函数类似于全局函数 map(func, *iterables),只是该函数将会启动多个线程,以异步方式立即对 iterables 执行 map 处理。

shutdown(wait=True):关闭线程池。

程序将 task 函数提交(submit)给线程池后,submit 方法会返回一个 Future 对象,Future 类主要用于获取线程任务函数的返回值。由于线程任务会在新线程中以异步方式执行,因此,线程执行的函数相当于一个“将来完成”的任务,所以 Python 使用 Future 来代表。

Future 提供了如下方法:

cancel():取消该 Future 代表的线程任务。如果该任务正在执行,不可取消,则该方法返回 False;否则,程序会取消该任务,并返回 True。

cancelled():返回 Future 代表的线程任务是否被成功取消。

running():如果该 Future 代表的线程任务正在执行、不可被取消,该方法返回 True。

done():如果该 Funture 代表的线程任务被成功取消或执行完成,则该方法返回 True。

result(timeout=None):获取该 Future 代表的线程任务最后返回的结果。如果 Future 代表的线程任务还未完成,该方法将会阻塞当前线程,其中 timeout 参数指定最多阻塞多少秒。

exception(timeout=None):获取该 Future 代表的线程任务所引发的异常。如果该任务成功完成,没有异常,则该方法返回 None。

add_done_callback(fn):为该 Future 代表的线程任务注册一个“回调函数”,当该任务成功完成时,程序会自动触发该 fn 函数。

在用完一个线程池后,应该调用该线程池的 shutdown() 方法,该方法将启动线程池的关闭序列。调用 shutdown() 方法后的线程池不再接收新任务,但会将以前所有的已提交任务执行完成。当线程池中的所有任务都执行完成后,该线程池中的所有线程都会死亡。

代码示例
'''
线程池能够提高性能,防止大量的线程而导致系统变慢,可以更简单的创建线程,适用于突发需要大量的线程,而线程存在时间短的场景
'''

from concurrent.futures import ThreadPoolExecutor
import time

def run(x):
    print(f'线程{x}')
    time.sleep(5)
    return x * 10


def callback(future):
    print(future.result())



if __name__=='__main__':
    # pool = ThreadPoolExecutor(max_workers=2)   #  同时工作的只能是两个线程,当其中的线程完成工作后,才能够启动后便的线程
    with ThreadPoolExecutor(max_workers=2) as pool:     # 这种方式,就可以不手动的关闭线程池

        #  启动三个线程
        future1 = pool.submit(run,1)
        future2 = pool.submit(run, 2)
        future3 = pool.submit(run, 3)
        # 查看线程1是否完成
        print(future1.done())
        time.sleep(3)
        # 查看线程2是否完成
        print(future2.done())



        future1.add_done_callback(callback())
        future3.add_done_callback(callback())
        # 获取线程1的返回值
        print(future1.result())

        # 获取线程3的返回值
        print(future3.result(timeout=1))   #   等待一秒钟,如果等待一秒之后还是没有获取到结果,就会产生报错信息

        pool.shutdown()   # 关闭线程池 ,等待已经启动的线程结束,才会关闭线程池。当关闭后再次添加线程池,就会产生报错信息

        print('程序完成')


        # 也会阻塞主线程
        result = pool.map(run,[7,8,9])    # 启动线程7、8、9
        print(result)
        for i in result:
            print(i)

        print('程序彻底结束了')

参考

线程池方法
队列方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值