线程队列、事件以及协程

线程的几个队列

都是从queue这个模块中导入

1、Queue队列(先进先出的队列)

from queue import Queue

q = Queue(maxsize=3) # 实例化产生队列对象
    # maxsize 设置队列里能容纳的最大的数据个数
q.put("first")
q.put("second")
q.put("third")  # 如果队列满了,put会阻塞住,等到空了再放进去

print(q.get())  # first
print(q.get())  # second
print(q.get())  # third     如果队列空了,get会阻塞住,等到有值再取出来
# 从结果中可以看出,queue.Queue 实例化出来的对象是先进先出

Queue

2、LifoQueue队列(先进后出的队列,lifo 是 last in first out缩写)

from queue import LifoQueue

q = LifoQueue()

q.put("first")
q.put("second")
q.put("third")

print(q.get())  # third
print(q.get())  # second
print(q.get())  # first
# 从结果可以看出,queue.LifoQueue 实例化出来的对象是先进的后出

LifoQueue

3、PriorityQueue队列(存储数据时可以设置优先级的队列)

  --1、如果只放一个元素,不用考虑元素能不能比较大小

  --2、只要队列里元素超过两个,那么元素之间必须可以支持比较大小

from queue import PriorityQueue

q = PriorityQueue()

q.put(item={"a":3}) # 这里需要注意的是,如果放入队列是多个元素,那么元素之间必须支持比大小
q.put({"A":2})

print(q.get())  # A
print(q.get())  # a     根据比较完的大小,小的先出

# 我们其实可以自定义一些类,然后给他添加比大小的方法,就可以比较大小了

PriorityQueue

事件Event

1、什么是事件

  事件表示在某个事件发生了某个事情的通知信号,用于线程间的协同工作

  因为不同线程之间是独立运行的状态不可预测,所以一个线程与另一个线程间的数据是不同步的,

  当一个线程需要利用另一个线程的状态来确定自己的下一步操作时,就必须保持线程间数据的同步

2、Event介绍

  event对象包含一个可由线程设置的信号标志,它允许线程等待某些事情发生后才执行

  在初始的情况下,event对象中的信号标志被设置为假,

  如果有一个线程等待一个event对象,而这个event对象的标志为假,那么将一直阻塞到标志变为真才接着执行

3、Event使用

可用方法

from threading import Event,Thread

e = Event()

e.set()     # 将event对象的标记设为True,所有被阻塞的线程就进入就绪态,等待操作系统调度
e.is_set()  # 返回event对象的标记状态
e.wait(timeout=2)    # 如果event对象的标记为False,那就阻塞,True就不阻塞
    # 里面可以设置超时时间,如果阻塞超过时间就会接着往下执行
e.clear()   # 把event对象的标记重新设为False

使用案例

# 需求是:两个任务并发执行,但是task2里的over必须要等到task1完毕才能执行
import time
from threading import Event,Thread

e = Event()

def task1():
    print("task1 run")
    time.sleep(3)
    print("task1 over")
    e.set() # task1 执行完毕,将事件对象设置为True,让task2里的阻塞变为就绪态,等待操作系统调度

def task2():
    print("task2 run")
    time.sleep(1)
    e.wait()    # 让他在这里等待,知道事件对象被设置为True
    print("task2 over")
Thread(target=task1).start()    # 这里简写,把创建对象和启动线程合并到一起
Thread(target=task2).start()

协程*****

协程的目的就是要在单线程中实现并发‘

为什么要在单线程内实现并发

  1、这样我们可以自己来掌控cpu运行的调度,只要cpu一过来,基本上就能把它的时间片用光,提高程序的效率

  2、当我们并发量比较高的时候,并且线程因为硬件原因已经不能再开启了,这是协程就是一个可以不占

    多少资源,又能实现并发的方法

单线程并发特点

  1、对于计算密集型任务而言,单线程并发并不能提高性能,反而会降低效率

  2、对于IO操作而言,必须具备能够检测IO操作,并自动切换到其他任务,这样才能提高效率

实现单线程并发的方式

1、yield保存状态 + 手动切换(了解)

  并发:多个任务看起来是同时运行,本质上是切换 + 保存状态

  在生成器中,yield就可以保存当前函数的运行状态

  所以我们可以简单通过yield来实现一个线程内的并发

  yield实现的方法是不能检测IO操作的

def task1():
    print("task1 first")
    yield
    print("task1 second")
    yield

def task2():
    print("task2 first")
    task1().__next__()      # 找到task1中第一个yield会返回来接着往下执行
    print("task2 second")
    task1().__next__()      # 需要注意的是,next方法必须要找到生成器中的yield,否则报错

task2() # 最终实现单线程间的并发

2、greenlet封装切换(了解)

  直接使用yield虽然能实现并发了,但是代码的结构太乱(到处都是yield和next),

  greenlet也是需要手动切换,并且不能检测IO操作

import greenlet

def task1():
    print("task1 first")
    g2.switch()
    print("task2 second")
    g2.switch()

def task2():
    print("task2 first")
    g1.switch()
    print("task2 second")

g1 = greenlet.greenlet(task1)
g2 = greenlet.greenlet(task2)

g1.switch() # 切换到g1去,执行完毕再接着往下执行,都是需要手动切换
print("main over")

3、gevent协程

  --1、什么是协程

     gevent 就是协程

     协程也是轻量级线程,也可以称之为微现场

     它是应用程序级别的任务调度方式

     它可以实现任务之间的自动切换,但是无法检测IO,需要和猴子补丁(monkey模块)一起使用

  --2、协程对比线程

    协程是应用程序级别调度,线程是操作系统级别调度

    应用程序级别的调度

      我们在检测到IO操作时,可以立马切换到我的其他任务来执行,如果有足够多的任务执行

      就可以把cpu的时间片充分利用起来

    操作系统级别的调度

      遇到IO,操作系统就会拿走cpu,下一次分给哪一个线程就要看操作系统内部算法,不是我们能决定的

    所以明显可以看出对于一个进程而言,使用协程的效率要高于使用多线的效率

  --3、如何提高效率(使用场景)

    在Cpython中,由于GIL锁的存在,导致多线程并不能并行,丧失了多核优势

    即使开启了多线程也只能并发,这时完全可以用协程来实现并发,提高程序的效率

    优点:不会占用更多无用的资源

    缺点:如果是计算密集型任务,使用协程反而降低效率

  --4、配合猴子补丁的用法

import time

from gevent import monkey
# 先导入monkey的类
monkey.patch_all()  # 可以修改一些阻塞代码变成非阻塞代码(具体可以修改哪些可以点进去看)

import gevent   # 导入gevent

def task1():
    print("task1 first")
    time.sleep(1)
    print("task1 second")

def task2():
    print("task2 first")
    print("task2 second")

g1 = gevent.spawn(task1)    # 创建协程
g2 = gevent.spawn(task2)

gevent.joinall([g1,g2]) # 注意的是主线程需要等待这些任务完成,不然主线程已结束,任务都不会执行
print("main over") # 运行结果也可以看出这些任务之间都是并发执行的,并且遇到IO可以自动切换

原文地址:https://www.cnblogs.com/hesujian/p/10994684.html

时间: 2024-11-08 10:50:57

线程队列、事件以及协程的相关文章

线程、进程、协程和队列

一.线程.进程 1.简述 进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动.它是操作系统动态执行的基本单元,通俗讲就是自定义一段程序的执行过程,即一个正在运行的程序.线程是进程的基本单位,又称为轻量级进程. * 不同的进程在内存中会开辟独立的地址空间,默认进程之间的数据是不共享,线程是由进程创建,所以处在同一个进程中的所有线程都可以访问该进程所包含的地址空间,当然也包含存储在该空间中的所有资源. 应用场景: IO密集型操作由于不占用CPU资源,所以一般使用线程来完成 计算密集型操作

Python基础—线程、进程和协程

今天已是学习Python的第十一天,来干一碗鸡汤继续今天的内容,今天的鸡汤是:超越别人对你的期望.本篇博客主要介绍以下几点内容: 线程的基本使用: 线程的锁机制: 生产者消费之模型(队列): 如何自定义线程池: 进程的基本使用: 进程的锁机制: 进程之间如何实现数据共享: 进程池: 协程的基本使用. 一.线程 1.创建线程 上篇博客已经介绍过如何创建多线程的程序,在这里在复习一下如何创建线程过程以及线程的一些方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1

python线程、进程和协程

链接:http://www.jb51.net/article/88825.htm 引言 解释器环境:python3.5.1 我们都知道python网络编程的两大必学模块socket和socketserver,其中的socketserver是一个支持IO多路复用和多线程.多进程的模块.一般我们在socketserver服务端代码中都会写这么一句: server = socketserver.ThreadingTCPServer(settings.IP_PORT, MyServer) Threadi

python小白-day8 线程、进程、协程

Python线程 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 1 2 3 4 5 6 7 8 9 10 11 12 13 #!/usr/bin/env python import threading import time def show(arg):     time.sleep(1)     print('thread'+str(arg)) for i

python线程、进程、协程

进程与线程之间的定义 计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分配.任务的调度. 程序是运行在系统上的具有某种功能的软件,比如说浏览器,音乐播放器等. 每次执行程序的时候,都会完成一定的功能,比如说浏览器帮我们打开网页,为了保证其独立性,就需要一个专门的管理和控制执行程序的数据结构——进程控制块. 进程就是一个程序在一个数据集上的一次动态执行过程. 进程一般由程序.数据集.进程控制块三

线程、进程、协程

一.线程 第一个线程 import threading #导入线程模块 def f1(arg): print(arg) t = threading.Thread(target=f1,args=(123,)) #定义一个线程任务,对象为f1,传入参数123 t.start() #执行线程任务 基本使用 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. 更多方法: start            线程准备就绪,等待CPU调度 setName      为线程设置名称 ge

Python之路【第七篇】:线程、进程和协程

Python之路[第七篇]:线程.进程和协程 Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/usr/bin/env python # -*- coding:utf-8 -*- import threading import time   def show(arg):     time.sleep(1)     print 'thread'+str(arg)   for i in

Python:简述 线程、进程和协程

Python线程 定义:Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. #!/usr/bin/env python # -*- coding:utf-8 -*- import threading import time def show(arg): time.sleep(1) print 'thread'+str(arg) for i in range(10): t = threading.Thread(target=show, args=(i,)) t.start(

线程、进程和协程

Treading用于提供线程相关的操作,线程是应用程序中工作的最小单元 #!/usr/bin/env python # coding:utf-8 import threading import time def show(arg): time.sleep(1) print 'thread'+str(arg) for i in range(10): t = threading.Thread(target=show,args=(i,)) t.start() print 'main thread st

Python:线程、进程与协程(1)——概念

最近的业余时间主要放在了学习Python线程.进程和协程里,第一次用python的多线程和多进程是在两个月前,当时只是简单的看了几篇博文然后就跟着用,没有仔细去研究,第一次用的感觉它们其实挺简单的,最近这段时间通过看书, 看Python 中文官方文档等等相关资料,发现并没有想想中的那么简单,很多知识点需要仔细去理解,Python线程.进程和协程应该是Python的高级用法.Python的高级用法有很多,看看Python 中文官方文档就知道了,当然有时间看看这些模块是怎么实现的对自己的提高是很有帮