1. 线程队列

1.1 先进先出(FIFO)

import queue

q = queue.Queue(3)
q.put('a')
q.put('b')
q.put('c') print(q.qsize()) # 队列大小
print(q.get())
print(q.get())
print(q.get())
print(q.get(timeout=2)) # 阻塞2s后报错
print(q.get(block=False)) # 阻塞后报错

1.2 后进先出(LIFO)堆栈

q = queue.LifoQueue(3)
q.put('a')
q.put('b')
q.put('c') print(q.qsize())
print(q.get())
print(q.get())
print(q.get())
"""
c
b
a
"""

1.3 优先级队列

# 自定义队列,数字越小优先级越高,元组形式
import queue q = queue.PriorityQueue(3)
q.put((0, 'a'))
q.put((-1, 'b'))
q.put((1, 'c')) print(q.qsize())
print(q.get())
print(q.get())
print(q.get())
"""
(-1, 'b')
(0, 'a')
(1, 'c')
"""

面试题:用列表实现队列和堆栈

lst = []
def add():
while 1:
msg = input('>>>').strip()
lst.append(msg)
if len(lst) > 3:
return lst def pop_lst(lst):
for i in range(len(lst)):
print(lst.pop(0)) # 队列
#print(lst.pop()) # 堆栈 lt = add()
pop_lst(lt) # 第二种加event from threading import Thread
from threading import Event event = Event()
lst = []
def add_queue():
while 1:
msg = input('>>>').strip()
lst.append(msg)
if len(lst) > 3:
event.set()
break def pop_queue(lst):
event.wait()
for i in range(len(lst)):
print(lst.pop()) # t1 = Thread(target=add_queue)
t2 = Thread(target=pop_queue,args=(lst,))
t1.start()
t2.start()

2. 事件event

​ 开启两个线程,一个线程运行到中间的某个阶段,触发另一个线程执行。两个线程增加了耦合性。

如果程序中的其他线程需要通过判断某个线程的状态来确定自己下一步的操作,就需要用threading中的Event模块。

# 一个线程监测服务器是否开启;另一个线程判断如果i哦开启,则能够连接成功,
# 此线程只能尝试连接三次,每次间隔1秒。
from threading import Thread
from threading import Event
from threading import current_thread
import time event = Event()
def check():
print(f"{current_thread().name}监测服务器是否开启...")
time.sleep(2)
event.set() # 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
print(f"{current_thread().name}服务器开启") def connect():
count = 1
while 1:
if count > 3:
print(f"{current_thread().name}超时,连接失败!")
break
event.wait(1) # 阻塞,直到event.set()方法之后,才会执行后面的代码;里面可以设置时间,1s后如果还没有event.set(),不等待,直接执行下一步。
print(f"{current_thread().name}等待连接第{count}次")
if event.is_set(): # 判断是否event.set()
print(f"{current_thread().name}连接成功!")
break
count += 1
t1 = Thread(target=ckeck, name="T1")
t2 = Thread(target=connect, name="T2")
t1.start()
t2.start()

3. 协程

并发的本质:切换 + 保持状态。

协程:是单线程下并发的处理任务,又称微线程、纤程。

协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。

过程:

开启协程并发执行,自己的程序把控着cpu在多个任务之间来回切换,并且保持状态。

协程切换速度非常快,蒙蔽了操作系统的监测,让操作系统认为cpu一直在运行你这个线程。(协程)

协程处理IO密集型效率高。

优点:

  1. 开销小;
  2. 运行速度快;
  3. 协程会长期霸占cpu,只执行程序里的所有任务,最大限度的利用cpu。

缺点:

  1. 本质是单线程下,无法利用多核;
  2. 一旦协程出现阻塞,将会阻塞整个线程,cpu也会被切走。

总结协程的特点

  1. 必须在只有一个单线程里实现并发;
  2. 修改共享数据不需加锁;
  3. 用户程序里自己保存多个控制流的上下文栈(能够保持状态);
  4. 一个协程的任务遇到IO操作自动切换到其他任务。

4. Greenlet 模块

from greenlet import greenlet

def eat(name):
print('%s eat 1' %name) #2
g2.switch('taibai') #3
print('%s eat 2' %name) #6
g2.switch() #7
def play(name):
print('%s play 1' %name) #4
g1.switch() #5
print('%s play 2' %name) #8 g1=greenlet(eat)
g2=greenlet(play)
g1.switch('taibai') #可以在第一次switch时传入参数,以后都不需要 1

​ 能够在任务之间直接切换,但是当切到一个任务执行时如果遇到io,那就会原地阻塞,仍然是没有解决遇到IO自动切换来提升效率的问题。

5. Gevent模块

第三方库,可以轻松通过gevent实现并发同步或异步编程,模式是Greenlet。特点就是,遇到IO阻塞就会自动切换任务

import gevent
import time
from gevent import monkey
monkey.patch_all() # 打补丁: 将下面的所有任务的阻塞都打上标记 def eat(name):
print('%s eat 1' %name)
time.sleep(2) # 阻塞,切换任务
print('%s eat 2' %name) def play(name):
print('%s play 1' %name)
time.sleep(1) # 阻塞,切换任务
print('%s play 2' %name) g1 = gevent.spawn(eat, 'meet')
g2 = gevent.spawn(play, 'meet')
gevent.joinall([g1,g2]) # 只有一个线程,因此需join
"""
meet eat 1
meet play 1
meet play 2
meet eat 2
""" # 如果两个任务同时遇到阻塞,切换一两次后操作系统会将cpu切走,程序挂起,当阻塞完毕后,会抢cpu,执行下面的代码。
一般在工作中我们都是进程+线程+协程的方式来实现并发,以达到最好的并发效果,如果是4核的cpu,一般起5个进程,每个进程中20个线程(5倍cpu数量),每个线程可以起500个协程,大规模爬取页面的时候,等待网络延迟的时间的时候,我们就可以用协程去实现并发。 并发数量 = 5 * 20 * 500 = 50000个并发,这是一般一个4cpu的机器最大的并发数。nginx在负载均衡的时候最大承载量就是5w个.
  单线程里的多个任务的代码通常会既有计算操作又有阻塞操作,我们完全可以在执行任务1时遇到阻塞,就利用阻塞的时间去执行任务2。。。。如此,才能提高效率,这就用到了Gevent模块。

python 38 线程队列与协程的更多相关文章

  1. 线程队列 concurrent 协程 greenlet gevent

    死锁问题 所谓死锁:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进 ...

  2. python day 20: 线程池与协程,多进程TCP服务器

    目录 python day 20: 线程池与协程 2. 线程 3. 进程 4. 协程:gevent模块,又叫微线程 5. 扩展 6. 自定义线程池 7. 实现多进程TCP服务器 8. 实现多线程TCP ...

  3. Python 37 进程池与线程池 、 协程

    一:进程池与线程池 提交任务的两种方式: 1.同步调用:提交完一个任务之后,就在原地等待,等任务完完整整地运行完毕拿到结果后,再执行下一行代码,会导致任务是串行执行 2.异步调用:提交完一个任务之后, ...

  4. python 之 并发编程(线程Event、协程)

    9.14 线程Event connect线程执行到event.wait()时开始等待,直到check线程执行event.set()后立即继续线程connect from threading impor ...

  5. Python 多线程、进程、协程上手体验

    浅谈 Python 多线程.进程.协程上手体验 前言:浅谈 Python 很多人都认为 Python 的多线程是垃圾(GIL 说这锅甩不掉啊~):本章节主要给你体验下 Python 的两个库 Thre ...

  6. Python多进程、多线程、协程

    转载:https://www.cnblogs.com/huangguifeng/p/7632799.html 首先我们来了解下python中的进程,线程以及协程! 从计算机硬件角度: 计算机的核心是C ...

  7. python并发编程之asyncio协程(三)

    协程实现了在单线程下的并发,每个协程共享线程的几乎所有的资源,除了协程自己私有的上下文栈:协程的切换属于程序级别的切换,对于操作系统来说是无感知的,因此切换速度更快.开销更小.效率更高,在有多IO操作 ...

  8. Python PEP 492 中文翻译——协程与async/await语法

    原文标题:PEP 0492 -- Coroutines with async and await syntax 原文链接:https://www.python.org/dev/peps/pep-049 ...

  9. python并开发编程之协程

    一 引出协成 并发的本质是:切换+保存状态 CPU在运行行一个任务时,会在两种情况下切走去执行其他任务,一是该任务发生了阻塞,二是运行该任务的时间过长 yeild可以保存状态,yeild状态保存与操作 ...

随机推荐

  1. 月薪12k的零基础自学前端必备手册

    随着互联网的深入发展,前端开发工程师一跃成为市场上非常抢手的人才.很多同学,包括以前做UI的.Java的.或者对于IT完全零基础的同学都想学习前端.下图是网上流传甚广的一张前端学习思维导图,很多初学者 ...

  2. VMware里装XP 没有找到硬盘驱动器

    遇到问题: 解决:要给虚拟机配上一个虚拟的硬盘驱动器.在VMWare的虚拟机配置里面给这个虚拟机增加硬盘,选IDE模式,而非SCSI,设定硬盘大小和文件名就可以了.

  3. 解读equals()和hashCode()

    前面部分摘自:https://blog.csdn.net/javazejian/article/details/51348320 一:Object中equals方法的实现原理 public boole ...

  4. Dubbo源码学习之-Adaptive自适应扩展

    前言 最近三周基本处于9-10-6与9-10-7之间,忙碌的节奏机会丢失了自己.除了之前干施工的那段经历,只看参加软件开发以来,前段时间是最繁忙的了.忙的原因,不是要完成的工作量大,而是各种环境问题, ...

  5. 基于SpringBoot从零构建博客网站 - 新增创建、修改、删除专栏功能

    守望博客是支持创建专栏的功能,即可以将一系列相关的文章归档到专栏中,方便用户管理和查阅文章.这里主要讲解专栏的创建.修改和删除功能,至于专栏还涉及其它的功能,例如关注专栏等后续会穿插着介绍. 1.创建 ...

  6. win7 磁盘碎片整理

    最近每天早上开机,都出现开机正常,但是所有软件都没法点开,性能特别差: 咨询了运维小伙伴,提示可以整理下电脑磁盘碎片试试.那么如何整理呢,如下详细说明 1.先整理C盘,打开我的电脑,在C盘上,右击-- ...

  7. JS面向对象编程(三):非构造函数的继承

    一.什么是"非构造函数"的继承?            现在有一个对象,叫"中国人".            var Chinese = {           ...

  8. iOS Xcode6 新建OC Category文件

    首先:File -> New File 接下来界面如下,选择Objective-C File,然后Next 在这里选择 Category 即可

  9. SpringMvc新建实例配置

    一.创建项目: 1.建立新的动态web项目: 2.为项目命名为:SpringMVC_01 3.添加tomcat运行时环境\依赖库  如果是MyEclipse的话创建web项目时就不需要此步骤 右键项目 ...

  10. 前端面试 js 你有多了解call,apply,bind?

    函数原型链中的 apply,call 和 bind 方法是 JavaScript 中相当重要的概念,与 this 关键字密切相关,相当一部分人对它们的理解还是比较浅显,所谓js基础扎实,绕不开这些基础 ...