python并发任务

本文详细介绍了Python中多线程的使用、线程池的概念、队列(包括FIFO、LIFO和优先级队列)以及协程和asyncio的原理和应用。重点讨论了如何控制线程执行顺序、队列操作和事件循环在协程中的作用。
摘要由CSDN通过智能技术生成

线程是执行用的,队列是存放结果用的

目录

1  多线程 threading

1.1  基本用法

1.2  循环使用

1.3  等待至线程终止 join()

1.4  一个线程打断另一个循环的线程

2  队列 queue

2.1  先进先出 queue.Queue()

2.2  后进先出 queue.LifoQueue()

2.3  优先级队列

2.4  队列阻塞

3  线程池

4  协程 asyncio

4.1  协程函数

4.2  事件循环

4.3  task对象

4.4  future对象

4.5  回调函数

4.6  向事件循环中添加多个协程任务

4.7  await


1  多线程 threading

1.1  基本用法

使用的库为threading,threading是python内置的库

我们每运行一个python文件相当于开启了一个进程,一个进程中有多个线程,如果使用了多线程我们可以在一段py代码中并行运行程序

我下面做个简单的例子

我们发现第一个任务运行的时候,第二个任务并没有等待第一个任务结束后再开始运行,而是开启了任务一后,直接开启任务二

1.2  循环使用

开始的时候会根据start()的顺序开始,结束的时候,线程各自执行不会等待其他的线程

1.3  等待至线程终止 join()

如果直接在start()后面打印的话,线程与print()会同时执行

如果加上了join()就会在线程结束的时候再打印

1.4  一个线程打断另一个循环的线程

一般来说我们的多线程都会写成无限循环然后根据条件跳出,代码大概是这样的

function()是需要被打断的任务。request请求模拟与下位机的交互

import time
import threading
import requests

def function():
    while True:
        try:
            print('开始执行')
            time.sleep(2)
            print('执行完毕')

            if stop == True:
                break
        except:
            pass

def break_function():
    global stop
    while True:
        try:
            time.sleep(0.5)
            response = requests.get('http://127.0.0.1:5000/stop').text
            if response == '停吧':
                stop = True
        except:
            pass


if __name__ == '__main__':
    t1 = threading.Thread(target=function)
    t2 = threading.Thread(target=break_function)

    t2.daemon = True

    t1.start()
    t2.start()

服务是模拟下位机的

from flask import Flask

app = Flask(__name__)

@app.route('/stop',methods=['GET'])
def stop():
    return '停吧1'

if __name__ == '__main__':
    app.run(host='0.0.0.0',debug=True)

当我把return的“停吧1”修改成“停吧”之后再启动一遍服务,那么function()任务就会被打断

(当我把return的“停吧1”修改成“停吧”之后再启动一遍服务)<- 这个就相当于是我手动按了一下按钮

线程可以分为守护线程和非守护线程两种。给线程的daemon设置为True,那么这个线程就会变成守护线程。如果不对线程的daemon进行设置的话,daemon默认为False,当daemon为False的时候线程为非守护线程。

一般一个程序只有一个非守护线程,当非守护线程终止时,所有的守护线程都会自动终止

2  队列 queue

队列常用于处理多线程产生的结果

2.1  先进先出 queue.Queue()

依次放入1,2,3三个值,然后取三次,发现可以成功的按顺序取出1,2,3

如果队列空了之后再取,就会无限等待 

2.2  后进先出 queue.LifoQueue()

依次放入1,2,3三个值,然后取三次,发现可以成功的按顺序取出3,2,1

如果队列空了之后再取,就会无限等待

2.3  优先级队列

依次放入(2, 'B') ,(1, 'A') ,(3, 'C') 。元组的第一个值是优先级,数字越小优先级越高

如果队列空了之后再取,就会无限等待

2.4  队列阻塞

在队列中取内容默认是阻塞的,将block置为False可以避免阻塞。避免阻塞后,如果拿不着数据会继续执行后面的内容,而不是死等

比如在多线程预测的时候,预测速度比较慢。我想保证画面的流畅性,那么我就不能预测一张展示一张,我只能让未预测的图像混合预测图像来搞,预测好了就插进来一帧,这样就流畅了

 

3  线程池

我们现在搞一个4线程的线程池,然后搞五个任务

Pool()中间的值是线程的个数,pool.map的第一个参数是要执行什么函数,第二个参数是函数的参数。pool.close()是不让别的线程再进入线程池。pool.join()是等待线程池中的所有线程结束再执行下面的代码。

我们通过上面的结果可以看出,一开始执行了4个任务,等一个任务完成后自动开始执行第五个任务

4  协程 asyncio

协程就有点像javascript的执行方式,比如javascript中写

打印A

定时器2s后打印B

打印C

执行的结果就是 先打印A,然后打印C,最后打印B。本身JS还是单线程的,打印A与打印C都在单线程中,最后打印B相当于是异步协程

单线程+异步协程相比于多线程会减少占用的资源,但执行时间要长于多线程,且写起来也比较麻烦(平时建议不使用协程,别人写了你能看懂就行了)

asyncio在jupyter notebook环境下执行会有问题

很多库是基于asyncio的,比如爬虫的alohttp

4.1  协程函数

通过关键字async装饰的函数是一个协程函数

执行协程函数得到的返回值是一个协程对象

协程函数不能直接调用

4.2  事件循环

协程函数可以放在事件循环中使用

通过asyncio.get_event_loop()创建事件循环对象

通过run_until_complete()执行协程函数

事件循环相当于一个任务调度站,可以理解为一个列表

创建协程的协程任务会放入事件循环

已完成的任务会删除,未完成的任务会被自动分配资源执行

如果事件循环中的任务全部完成就中断循环

4.3  task对象

task就是执行协程函数的另一种方式,使用create_task()创建task对象

4.4  future对象

future也是是执行协程函数的一种方式,使用asyncio.ensure_future()创建future对象

4.5  回调函数

回调函数是执行完协程函数后执行的函数,通过add_done_callback()添加回调函数,回调函数中可以通过.result获取协程函数的返回值

可以给future对象添加

也可以给task对象添加

  • future能干的task基本都能干,后面就不特别演示了

4.6  向事件循环中添加多个协程任务

首先你搞一个列表,列表里放future对象(或task对象),然后最后使用asyncio.wait()来执行future列表

4.7  await

python中的await与js中的await的含义完全不同。在python中await是挂起协程函数,比如

  • 在js中await是等待await执行完毕之后再执行别的,python本身是同步的,通过async变成异步。JS本身是异步的,通过async变为同步

asyncio.sleep(1)相当于是异步的等待,一到sleep就通过await给它挂起,所以代码只运行了1s多,而不是3s多

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Suyuoa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值