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. MongoDB 启动时关于 NUMA 警告 的分析----(To avoid performance problems)

    1. 需求描述 观察MongoDB的启动Log,会看到一个关于  NUMA 的警告 和 优化建议 --17T17:: I CONTROL [initandlisten] ** WARNING: You ...

  2. [HDOJ] 2026.Max Sum

    2026.Max Sum (c++) Problem Description Consider the aggregate An= { 1, 2, -, n }. For example, A1={1 ...

  3. [02] HEVD 内核漏洞之栈溢出

    作者:huity出处:http://www.cnblogs.com/huity35/版权:本文版权归作者所有.文章在看雪.博客园.个人博客同时发布.转载:欢迎转载,但未经作者同意,必须保留此段声明:必 ...

  4. CCNA笔记(一)

    R1#enable R1#configure terminal R1(config)#interface fastEthernet 0/0R1(config-if)#ip address 12.1.1 ...

  5. hdu多校第八场Parentheses Matrix

    #include<bits/stdc++.h> using namespace std; ][]; int main() { int t; scanf("%d",&am ...

  6. CSS3☞transform变换

    transform CSStransform属性允许你旋转,缩放,倾斜或平移给定元素.这是通过修改CSS视觉格式化模型的坐标空间来实现的. DEMO /* Keyword values */ tran ...

  7. 【Android Studio】提示代码忽略大小写

    在 Preference... 中找到如下,设置 Case sensitive completion 为 None 即可,如下图: PS: 该截图是 Intellij IDEA (Android St ...

  8. 【iOS】Updating local specs repositories

    使用 Pods 时遇到这个问题,原因是被墙了……需换成下面命令: pod install --verbose --no-repo-update

  9. 一文了解:Redis事务

    Redis事务 事务提供了一种"将多个命令打包,一次性提交并按顺序执行"的机制,提交后在事务执行中不会中断.只有在执行完所有命令后才会继续执行来自其他客户的消息. Redis中的使 ...

  10. Ok-Http | Android 网络请求框架使用方式

    POST : package he3.sd.util; import com.parkingwang.okhttp3.LogInterceptor.LogInterceptor; import jav ...