一、 异步与回调机制  

问题:

1、任务的返回值不能得到及时的处理,必须等到所有任务都运行完毕才能统一进行处理

2、解析的过程是串行执行的,如果解析一次需要花费2s,解析9次则需要花费18s

解决一: (线程实现异步,回调解析结果)    

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
from threading import current_thread
import requests
import os
import time
import random def get(url):
print('%s GET %s' %(current_thread().name,url))
response=requests.get(url)
time.sleep(random.randint(1,3)) if response.status_code == 200:
# 干解析的活
return response.text def pasrse(obj):
res=obj.result()
print('%s 解析结果为:%s' %(current_thread().name,len(res))) if __name__ == '__main__':
urls=[
'https://www.baidu.com',
'https://www.baidu.com',
'https://www.baidu.com',
'https://www.baidu.com',
'https://www.baidu.com',
'https://www.baidu.com',
'https://www.baidu.com',
'https://www.baidu.com',
'https://www.python.org',
]
pool=ThreadPoolExecutor(4)
for url in urls:
obj=pool.submit(get,url) #放入进程池,实现异步操作
obj.add_done_callback(pasrse) #回调,将线程执行结果当作参数传递给pasrse函数,线程是谁先空闲谁执行结果处理,不存在主次之分 print('主线程',current_thread().name)

   

     解决二: (进程实现异步,回调解析结果)

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import requests
import os
import time
import random def get(url):
print('%s GET %s' %(os.getpid(),url))
response=requests.get(url)
time.sleep(random.randint(1,3)) if response.status_code == 200:
# 干解析的活
return response.text def pasrse(obj):
res=obj.result()
print('%s 解析结果为:%s' %(os.getpid(),len(res))) if __name__ == '__main__':
urls=[
'https://www.baidu.com',
'https://www.baidu.com',
'https://www.baidu.com',
'https://www.baidu.com',
'https://www.baidu.com',
'https://www.baidu.com',
'https://www.baidu.com',
'https://www.baidu.com',
'https://www.python.org',
] pool=ProcessPoolExecutor(4)
for url in urls:
obj=pool.submit(get,url) #放入进程池,实现异步操作
obj.add_done_callback(pasrse) #回调,将进程执行结果当作参数传递给pasrse函数,由主进程执行 print('主进程',os.getpid())

二、线程queue

import queue

q=queue.Queue(3) #队列:先进先出
q.put(1)
q.put(2)
q.put(3)
# q.put(4) print(q.get())
print(q.get())
print(q.get()) q=queue.LifoQueue(3) #堆栈:后进先出 q.put('a')
q.put('b')
q.put('c') print(q.get())
print(q.get())
print(q.get()) q=queue.PriorityQueue(3) #优先级队列:可以以小元组的形式往队列里存值,第一个元素代表优先级,数字越小优先级越高
q.put((10,'user1'))
q.put((-3,'user2'))
q.put((-2,'user3')) print(q.get())
print(q.get())
print(q.get())

三、线程Event   

from threading import Event,current_thread,Thread
import time event=Event() # 监听信号 初始值为False def check():
print('%s 正在检测服务是否正常....' %current_thread().name)
time.sleep(5)
event.set() #set 方法将信号值 置为True def connect():
count=1
while not event.is_set(): #判断标记为是否为True
if count == 4:
print('尝试的次数过多,请稍后重试')
return
print('%s 尝试第%s次连接...' %(current_thread().name,count))
event.wait(1) #括号里的是等待时间,程序想继续运行,除非标志位为True或者超时,此处超时不会报错,是继续执行
count+=1
print('%s 开始连接...' % current_thread().name) if __name__ == '__main__':
t1=Thread(target=connect)
t2=Thread(target=connect)
t3=Thread(target=connect) c1=Thread(target=check) t1.start()
t2.start()
t3.start()
c1.start()

四、协程    

1、单线程下实现并发:协程

并发指的多个任务看起来是同时运行的

并发实现的本质:切换+保存状态

2、并发、并行、串行:

并发:看起来是同时运行,切换+保存状态
并行:真正意义上的同时运行,只有在多cpu的情况下才能
实现并行,4个cpu能够并行4个任务

串行:一个人完完整整地执行完毕才运行下一个任务

import time
def consumer():
'''任务1:接收数据,处理数据'''
while True:
x=yield def producer():
'''任务2:生产数据'''
g=consumer()
next(g)
for i in range(10000000):
g.send(i) start=time.time()
#基于yield保存状态,实现两个任务直接来回切换,即并发的效果
#PS:如果每个任务中都加上打印,那么明显地看到两个任务的打印是你一次我一次,即并发执行的.
producer() #1.0202116966247559 stop=time.time()
print(stop-start)

    并不是所有协程都能提升效率,如果是IO密集型的,协程会提高执行效率,然而计算密集型的切换并不能提高效率,反而会降低效率

五、单线程下实现遇到IO切换

    1、greentlet可以切换,但不能遇到IO切  

from greenlet import greenlet
import time def eat(name):
print('%s eat 1' %name)
time.sleep(30)
g2.switch('alex') #遇到switch切换
print('%s eat 2' %name)
g2.switch()
def play(name):
print('%s play 1' %name)
g1.switch()
print('%s play 2' %name) g1=greenlet(eat)
g2=greenlet(play) g1.switch('egon')

·    

    2、gevent切换,只能识别自己的IO操作,无法数别系统定义的IO,如time.sleep()

import gevent

def eat(name):
print('%s eat 1' %name)
gevent.sleep(5) #gevent自定义的IO 可切换
print('%s eat 2' %name)
def play(name):
print('%s play 1' %name)
gevent.sleep(3)
print('%s play 2' %name) g1=gevent.spawn(eat,'egon')
g2=gevent.spawn(play,'alex') # g1.join()
# g2.join()
gevent.joinall([g1,g2]) #无法识别,不能切换
from gevent import monkey;monkey.patch_all()
import gevent
import time def eat(name):
print('%s eat 1' %name)
time.sleep(5) #无法识别,不能切换
print('%s eat 2' %name)
def play(name):
print('%s play 1' %name)
time.sleep(3)
print('%s play 2' %name) g1=gevent.spawn(eat,'egon')
g2=gevent.spawn(play,'alex') # g1.join()
# g2.join()
gevent.joinall([g1,g2])

3、若想要实现系统定义的IO切换需加上       

import monkey;monkey.patch_all()

eg:

from gevent import monkey;monkey.patch_all()
from threading import current_thread
import gevent
import time def eat():
print('%s eat 1' %current_thread().name)
time.sleep(5)
print('%s eat 2' %current_thread().name)
def play():
print('%s play 1' %current_thread().name)
time.sleep(3)
print('%s play 2' %current_thread().name) g1=gevent.spawn(eat)
g2=gevent.spawn(play) # gevent.sleep(100)
# g1.join()
# g2.join()
print(current_thread().name)
gevent.joinall([g1,g2])

4月28日 python学习总结 线程与协程的更多相关文章

  1. 5月28日 python学习总结 CSS学习(二)

    CSS属性相关 宽和高 width属性可以为元素设置宽度. height属性可以为元素设置高度. 块级标签才能设置宽度,内联标签的宽度由内容来决定. 字体属性 文字字体 font-family可以把多 ...

  2. 5月28日 python学习总结 CSS学习(一)

    1. CSS是什么 层叠样式表 --> 给HTML添加样式的 2. CSS的语法 选择器 { 属性1:值1; 属性2:值2; } 3. CSS引入方式 1. 直接写在HTMl标签里面 <p ...

  3. Python—进程、线程、协程

    一.线程 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务 方法: ...

  4. python 进程、线程与协程的区别

    进程.线程与协程区别总结 - 1.进程是计算器最小资源分配单位 - 2.线程是CPU调度的最小单位 - 3.进程切换需要的资源很最大,效率很低 - 4.线程切换需要的资源一般,效率一般(当然了在不考虑 ...

  5. Python进程、线程、协程及IO多路复用

    详情戳击下方链接 Python之进程.线程.协程 python之IO多路复用

  6. Python 进程、线程、协程、锁机制,你知多少?

    1.python的多线程到底有没有用? 2. 为什么在python里推荐使用多进程而不是多线程 3.进程.线程.协程.各种锁 4.Python多进程编程

  7. Python进程、线程、协程的对比

    1. 执行过程 每个线程有一个程序运行的入口.顺序执行序列和程序的出口.但是线程不能够独立执行,必须依存在进程中,由进程提供多个线程执行控制.每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该 ...

  8. 4月2日 python学习总结

    昨天内容回顾: 1.迭代器 可迭代对象: 只要内置有__iter__方法的都是可迭代的对象 既有__iter__,又有__next__方法 调用__iter__方法==>得到内置的迭代器对象 调 ...

  9. 4月8日 python学习总结 模块与包

    一.包 #官网解释 Packages are a way of structuring Python's module namespace by using "dotted module n ...

随机推荐

  1. python语法_1基础语法概述

    http://www.runoob.com/python3 章节:教程.基础语法.数据类型.解释器.注释.运算符. 大纲 查看python版本 实现第一个python3.x程序,hello world ...

  2. 如何通过opensea-js获取OpenSea的数据

    OpenSea作为NFT最大的交易平台,随着NFT的火热之后,热度也是出现翻天覆地的变化.作为开发人员肯定好奇有没有可以与opensea交互的包来开发相关的工具或者快速获取opensea的数据.别急, ...

  3. tarjan2

    反过来调过去,我还是感觉没学明白缩点 讲一个有向图中的所有强连通分量缩成一个点后,构成的新图是一个DAG. 一个点所在的强连通分量一定被该点所在DFS搜索树所包含 树上的边大致分为:树枝边,前向边(从 ...

  4. 微服务从代码到k8s部署应有尽有系列(二、网关)

    我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ...

  5. 常用文本处理命令 & 三剑客之 sed

    今日内容 文本处理命令 Linux 三剑客之 sed 内容详细 文本处理命令 1.sort : 文件内容排序 默认按照文件隔行内容的第一个字符大小进行排序(默认是升序) 默认输出文本结果 sort [ ...

  6. Note -「Min_25 筛」“你就说这素因子你要不要吧?你要不要?”

      赛上想写,Track Lost 了属于是. \(\mathscr{Intro}\)   Min_25 筛是用于求积性函数前缀和,同时顺带求出一些"有意思"的信息的筛法.   一 ...

  7. Solution -「CF 1392H」ZS Shuffles Cards

    \(\mathcal{Description}\)   Link.   打乱的 \(n\) 张编号 \(1\sim n\) 的数字排和 \(m\) 张鬼牌.随机抽牌,若抽到数字,将数字加入集合 \(S ...

  8. CentOS 7.6 部署 GlusterFS 分布式存储系统

    文章目录 GlusterFS简介 环境介绍 开始GlusterFS部署 配置hosts解析 配置GlusterFS 创建文件系统 安装GlusterFS 启动GlusterFS 将节点加入到主机池 创 ...

  9. opencv安装实录附十几行C++实现的一个人脸识别demo

    前言: 之前写过一篇在nano上使用opencv,nano上默认是安装了opencv的库,除了nano,我们自己电脑上也想使用opencv做一些平时图像处理验证. 本来也是看一些资料安装好的,觉得也没 ...

  10. leetcode算法13.罗马数字转整数

    哈喽!大家好,我是[学无止境小奇],一位热爱分享各种技术的博主! [学无止境小奇]的创作宗旨:每一条命令都亲自执行过,每一行代码都实际运行过,每一种方法都真实实践过,每一篇文章都良心制作过. [学无止 ...