同步异步与协程

目录:

    同步/异步

    异步回调

    协成

    线程队列

同步|异步:

线程的三种状态:
  1.就绪
  2.运行
  3.阻塞
阻塞和非阻塞描述的是运行的状态
阻塞 :遇到了IO操作,代码卡住,无法执行下一行,CPU会切换到其他任务
非阻塞 :与阻塞相反,代码正在执行(运行状态) 或处于就绪状态

同步和异步指的是提交任务的方式
同步 :提交任务必须等待任务完成,才能执行下一行
异步 :提交任务不需要等待任务完成,立即执行下一行

代码:

 1 def task():
 2     for i in range(1000000):
 3         i += 1000
 4     print("11111")
 5 
 6 print("start")
 7 task() # 同步提交方式,等函数运行完菜执行下一行
 8 print("end")
 9 
10 from threading import  Thread
11 
12 print("start1")
13 Thread(target=task).start() # 异步提交,开启线程,然后去执行之后的代码,线程内代码自行执行
14 print("end1")

异步回调:任务执行结束后自动调用某个函数

异步回调:
  在发起异步任务后,子进程或子线程完成任务后需要通知任务发起方.通过调用一个函数,all_done_callback(函数名)
为什么需要回调?子进程帮助主进程完成任务,处理任务的结果应该交还给主进程 其他方式也可以将数据交还给主进程
1.shutdown 主进程会等到所有任务完成2.result函数 会阻塞直到任务完成都会阻塞,导致效率降低,所以使用回调 注意:回调函数什么时候被执行? 子进程任务完成时谁在执行回调函数? 主进程 线程的异步回调使用方式都相同,唯一的不同是执行回调函数,是子线程在执行(线程间数据共享)

三种方式:

 1 # 方式1 自己来保存数据 并执行shutdown  仅在多线程
 2 
 3 res = []
 4 def task():
 5     print("%s is 正在打水" % os.getpid())
 6     time.sleep(0.2)
 7     w = "%s 打的水" % os.getpid()
 8     res.append(w)
 9     return w
10 
11 if __name__ == '__main__':
12     for i in range(20):
13         # 提交任务会返回一个对象  用于回去执行状态和结果
14         f = pool.submit(task)
15         print(f.result()) # 方式2   执行result 它是阻塞的直到任务完成  又变成串行了
16 
17     print("11111")
18     # pool.shutdown() # 首先不允许提交新任务 然后等目前所有任务完成后
19     # print(res)
20     print("over")
21 
22 ====================================================================================
23 
24 pool = ThreadPoolExecutor()
25 
26 # 方式3 通过回调(什么是回调 任务执行结束后自动调用某个函数)
27 def task():
28     print("%s is 正在打水" % os.getpid())
29     # time.sleep(0.2)
30     w = "%s 打的水" % os.getpid()
31     return w
32 
33 def task_finish(res):
34     print("打水完成! %s" % res)
35 
36 if __name__ == '__main__':
37     for i in range(20):
38         # 提交任务会返回一个对象  用于回去执行状态和结果
39         f = pool.submit(task)
40         f.add_done_callback(task_finish) #添加完成后的回调
41     print("11111")
42     print("over")

利用回调完成生产者消费者:

多进程:
1 from  concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor2 from threading import current_thread3 import  os4 # 进程池5 pool = ProcessPoolExecutor()6 # 爬虫:从网络某个地址获取一个HTML文件7 import requests # 该模块用于网络(HTTP)请求8 9 # 生产数据,即生产者
10 def get_data_task(url):
11     print(os.getpid(),"正在生产数据!")
12     # print(current_thread(),"正在生产数据!")
13 
14     response = requests.get(url)
15     text = response.content.decode("utf-8")
16     print(text)
17     return text
18 
19 # 处理数据,即消费者
20 def parser_data(f):
21     print(os.getpid(),"处理数据")
22     # print(current_thread(), "处理数据")
23     print("正在解析: 长度%s" % len(f.result()))
24 
25 urls = [
26     "http://www.baidu.com",
27     "http://www.baidu.com",
28     "http://www.baidu.com",
29     "http://www.baidu.com"
30 ]
31 
32 if __name__ == '__main__':
33     for url in urls:
34         f = pool.submit(get_data_task,url)
35         f.add_done_callback(parser_data)  # 回调函数是主进程在执行
36         # 因为子进程是负责获取数据的,然而数据怎么处理 ,子进程并不知道.应该把数据还给主进程
37     print("over")
多线程:
 1 from  concurrent.futures import ThreadPoolExecutor
 2 from threading import current_thread
 3 # 进程池
 4 pool = ThreadPoolExecutor()
 5 
 6 # 爬虫:从网络某个地址获取一个HTML文件
 7 import requests # 该模块用于网络(HTTP)请求
 8 
 9 # 生产数据
10 def get_data_task(url):
11     # print(os.getpid(),"正在生产数据!")
12     print(current_thread(),"正在生产数据!")
13 
14     response = requests.get(url)
15     text = response.content.decode("utf-8")
16     print(text)
17     return text
18 
19 #   处理数据
20 def parser_data(f):
21     # print(os.getpid(),"处理数据")
22     print(current_thread(), "处理数据")
23     print("正在解析: 长度%s" % len(f.result()))
24 
25 urls = [
26     "http://www.baidu.com",
27     "http://www.baidu.com",
28     "http://www.baidu.com",
29     "http://www.baidu.com"
30 ]
31 
32 if __name__ == '__main__':
33     for url in urls:
34         f = pool.submit(get_data_task,url)
35         f.add_done_callback(parser_data)  # 回调函数是主进程在执行
36         # 因为子进程是负责获取数据的  然而数据怎么处理 子进程并不知道  应该把数据还给主进程
37     print("over")

 线程队列:

普通队列/堆栈队列/优先级队列:

import queue# 普通队列 先进先出
q = queue.Queue()
q.put("a")
q.put("b")print(q.get())
print(q.get())# 堆栈队列  先进后出 后进先出  函数调用就是进栈  函数结束就出栈 递归造成栈溢出
q2 = queue.LifoQueue()
q2.put("a")
q2.put("b")
print(q2.get())# 优先级队列
q3 = queue.PriorityQueue()  # 数值越小优先级越高  优先级相同时 比较大小 小的先取
q3.put((-100, "c"))
q3.put((1, "a"))
q3.put((100, "b"))
print(q3.get())

协程:在单线程下由应用程序级别实现并发

什么是协程?协程指的是单线程下由应用程序级别实现的并发即把本来由操作系统控制的切换+保存状态,在应用程序里实现了协程的切换vs操作系统的切换优点:切换速度远快于操作系统缺点:一个任务阻塞了,其余的任务都无法执行ps:只有遇到io才切换到其他任务的协程才能提升单线程的执行效率为何用协程?把单个线程的io降到最低,最大限度地提升单个线程的执行效率如何实现协程?from gevent import spawn,monkey;monkey.patch_all()
协程的目的是在单线程下实现并发
为什么出现协程? 因为cpython中,由于GIL而导致同一时间只有一个线程在跑
意味着:如果你的程序时计算密集,多线程效率也不会提升如果是io密集型 没有必要在单线程下实现并发,我会开启多线程来处理io,子线遇到io,cpu切走.不能保证一定切到主线如果可以,我在遇到io的时候转而去做计算,这样一来可以保证cpu一直在处理你的程序,当然处理时间太长也要切走总结:单线程下实现并发,是将io阻塞时间用于执行计算,可以提高效率原理:一直使用CPU直到超时
怎么实现单线程并发?并发:指的是看起来像是同时运行,实际是在任务间来回切换,同时需要保存执行的状态任务一堆代码  可以用函数装起来1.如何让两个函数切换执行yield可以保存函数的执行状态通过生成器可以实现伪并发并发不一定提升效率,当任务全是计算时,反而会降低效率2.如何知道发生了io, 从而切换执行?第三方模块,gevent
第三方模块 greenlet 可以实现并发 但是不能检测io
第三方模块 gevent 封装greenlet 可以实现单线程并发,并且能够检测io操作,自动切换
协程的应用场景:
TCP 多客户端实现方式
1.来一个客户端就来一个进程 资源消耗较大
2.来一个客户端就来一个线程 也不能无限开
3.用进程池 或 线程池 还是一个线程或进程只能维护一个连接
4.协程 一个线程就可以处理多个客户端 遇到io就切到另一个

协成实现:单线程实现并发

 

1.yield 把函数做成生成器,生成器会自动保存状态

 1 # 这是一个进程,默认包含一个主线程
 2 import time
  #生成器函数
3 def task(): 4 while True: 5 print("task1") 6 time.sleep(1)#I/O,CPU切走 7 yield 1 8 9 def task2(): 10 g = task() 11 while True: 12 try: 13 print("task2") 14 next(g)#next()函数参数传一个可迭代对象 15 except Exception: 16 print("任务完成") 17 break 18 task2() 19 打印结果: 20 task2 21 task1 22 task2 23 task1 24 task2 25 task1 26 ..........

2.greenlet模块:帮我们封装yield,可以实现任务切换,但是不能检测I/O

# 1.实例化greenlet得到一个对象,传入要执行的任务,至少需要两个任务
# 2.先让某个任务执行起来,使用对象调用switch
# 3.在任务的执行过程中,手动调用switch来切换
 1 import greenlet
 2 import time
 3 def task1():
 4     print("task1 1")
 5     time.sleep(2)
 6     g2.switch()
 7     print("task1 2")
 8     g2.switch()
 9 
10 def task2():
11     print("task2 1")
12     g1.switch()
13     print("task2 2")
14 
15 g1 = greenlet.greenlet(task1)
16 g2 = greenlet.greenlet(task2)
17 
18 g1.switch()

3.gevent:在greenlet的基础上封装检测io操作,自动切换

# 1.spawn函数传入你的任务
# 2.调用join 去开启任务
# 3.检测io操作需要打monkey补丁,就是一个函数,在程序最开始的地方调用它
 1 from gevent import monkey
 2 monkey.patch_all()
 3 
 4 import gevent
 5 import time
 6 def eat():
 7     print('eat food 1')
 8     time.sleep(2)
 9     print('eat food 2')
10 
11 def play():
12     print('play 1')
13     time.sleep(1)
14     print('play 2')
15 
16 g1=gevent.spawn(eat)
17 g2=gevent.spawn(play)
18 
19 gevent.joinall([g1,g2])
20 print('')

 协程实现TCP:

服务端:
 1 import gevent
 2 from gevent import monkey
 3 monkey.patch_all()
 4 import socket
 5 
 6 server = socket.socket()
 7 # 重用端口
 8 server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
 9 
10 server.bind(("127.0.0.1",9999))
11 
12 server.listen(5)
13 def data_handler(conn):
14     print("一个新连接..")
15     while True:
16         data = conn.recv(1024)
17         conn.send(data.upper())
18 
19 while True:
20     conn,addr = server.accept()
21     # 切到处理数据的任务去执行
22     gevent.spawn(data_handler,conn)
客户端:
 1 import socket
 2 
 3 c = socket.socket()
 4 
 5 c.connect(("127.0.0.1", 9999))
 6 
 7 while True:
 8     msg = input(">>>:")
 9     if not msg: continue
10     c.send(msg.encode("utf-8"))
11     data = c.recv(1024)
12     print(data.decode("utf-8"))
View Code 

转载于:https://www.cnblogs.com/xuechengeng/p/9954936.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/352219.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux禁止非WHEEL用户使用SU命令

通常情况下,一般用户通过执行“su -”命令、输入正确的root密码,可以登录为root用户来对系统进行管理员级别的配置。 但是,为了更进一步加强系统的安全性,有必要建立一个管理员的 组,只允许这个组的用户来执行“su -”…

代理的JavaOne 2016观察

我无法参加JavaOne 2016,因此很高兴在线上看到大量资源,这些资源使我能够基于JavaOne 2016内容进行观察。 我在本文中引用并简要描述了其中的一些JavaOne 2016资源,并根据这些资源的使用添加了我自己的一些观察结果。 正如Katharine在JavaOne…

resnet过拟合_重读经典:完全解析特征学习大杀器ResNet

公众号关注 “ML-CVer”设为 “星标”,DLCV消息即可送达!作者丨刘昕宸知乎来源丨https://zhuanlan.zhihu.com/p/268308900编辑丨极市平台导读 通过堆叠神经网络层数(增加深度)可以非常有效地增强表征,提升特征学习效果,但是会出现…

Java开发笔记(二十三)数组工具Arrays

数组作为一种组合形式的数据类型,必然要求提供一些处理数组的简便办法,包括数组比较、数组复制、数组排序等等。为此Java专门设计了Arrays工具,该工具包含了几个常用方法,方便程序员对数组进行加工操作。Arrays工具的方法说明如下…

生成对抗网络gan原理_必读!TOP10生成对抗网络GAN论文(附链接)

来源:新智元本文约2200字,建议阅读7分钟。本文所选论文提供了一个易读的对GAN的介绍,帮助你理解GAN技术的基础。[ 导读 ]生成对抗网络 (GAN) 是深度学习中最有趣、最受欢迎的应用之一。本文列出了 10 篇关于 GAN 的论文,这些论文将…

visudo精确用户赋权(sudo)

原文BLOG:http://iminmin.blog.51cto.com/689308/455992sudo” 是 Unix/Linux 平台上的一个非常有用的工具,允许为非根用户赋予一些合理的 “ 权利 ” ,让他们执行一些只有根用户或特许用户才能完成的任务,从而减少根用户的登陆次…

es6中的类及es5类的实现

目录 类的特点类的特点 1.类只能通过new得到 在es6中类的使用只能是通过new,如果你将它作为一个函数执行,将会报错。 //es6的写法 class Child {constructor() {this.name 1;} } let child new Child(); console.log(child.name)//1 //如果直接…

python高阶函数filter_Python进阶系列连载(13)——Python内置高阶函数filter(上)...

前言进阶部分连载继续~如果还没看过我的入门连载部分,先看:当然,小编的免费入门课程已经有咯,看过连载的朋友可以看看视频再快速梳理一遍~前文传送门:filterfilter是什么意思呢?我们百度看看:百…

javaone_JavaOne 2012:观察与印象

javaone我正坐在旧金山国际机场等待登上一架飞机,然后又一次满意但累人的JavaOne(2012)体验,开始撰写这篇特别的博客文章。 自上周日的主题演讲以来,在会议上狂热地撰写了约30篇博客文章之后,再写另一篇博客…

CSDN转载博客的方法

前言 对于喜欢逛CSDN的人来说,看别人的博客确实能够对自己有不小的提高,有时候看到特别好的博客想转载下载,但是不能一个字一个字的敲了,这时候我们就想快速转载别人的博客,把别人的博客移到自己的空间里面&#xff0c…

linux 服务器账号及安全杂谈

1、useradd zhangsan,添加zhangsan用户后,不能交互式登陆该账号。 原因是:/etc/shadow中内容是 zhangsan:!!:16804:0:99998:7::: 其中,两个!!表示出于安全角度,不能登陆。给zhangsan设置密码后,就可以登陆…

mysql-9索引

mysql索引的建立对于mysql的高效运行是很重要的,索引可以大大提高mysql的检索速度。 索引分为单列索引和组合索引。 单列索引,即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引。 组合索引,即一个索…

带有AWS Lambda和Java的无服务器FaaS

什么是无服务器架构? 无服务器架构在由第三方完全管理的临时容器中运行自定义代码。 自定义代码通常只是完整应用程序的一小部分。 也称为函数 。 这为无服务器架构提供了另一个名称,即功能即服务 (FaaS)。 该容器是短暂的&#x…

python 查找算法_七大查找算法(Python)

查找算法 -- 简介查找(Searching)就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素。查找表(Search Table):由同一类型的数据元素构成的集合关键字(Key):数据元素中某个数据项的值,又称为键值主键(Primary K…

traceroute命令的用法实例

ceroute命令的用法实例traceroute 跟踪数据包到达网络主机所经过的路由工具;traceroute 是用来发出数据包的主机到目标主机之间所经过的网关的工具。traceroute 的原理是试图以最小的TTL发出探测包来跟踪数据包到达目标主机所经过的网关,然后监听一个来自…

去除div最后一个逗号_去除重复值、统计数量,这个公式可以直接套用!

点击上方蓝字关注星标★不迷路本文作者:拉登 Dony来源:拉小登(ID:ladengchupin)本文编辑:小叮、竺兰前段时间遇到这样一个问题,让我很头疼。头疼的原因有 3 点:❶ 问题描述不清晰,理解起来困难&…

spring shell_Spring Shell项目发布

spring shellSpring Source昨天发布了Spring Shell 。 Spring Shell是一个交互式Shell,可以使用基于Spring的编程模型轻松地通过命令进行扩展。 它是通过删除OSGi依赖项从Spring Roo项目中提取的,并变成了一个独立项目。 这使得那些只希望使用交互式外壳…

Word报告自动生成(例如 导出数据库结构)

将很早之前写的一个小组件重新整理优化一下,做成一个通用的功能。适用于导出数据库的结构(表、字段等)到Word或将体检数据自动生成Word版的体检报告等。代码:Github 一、主要需要完成功能: 1. 灵活的配置规则及word样式设置&#…

马尔科夫随机场

1、相关概念 马尔科夫随机过程:在已知当前状态的情况下,未来的状态只与当前状态有关,与过去状态无关。这种已知“现在”的条件下,“未来”和“过去”彼此独立的特性叫做马尔科夫性,具有这种特性的随机过程叫做马尔科夫…

php上传文件详解

上传文件功能由两个部分组成&#xff0c;HTML页面和PHP处理部分。HTML页面主要是让用户选择所要上传的文件&#xff0c;php部分让我们可以把文件存储到服务器的指定目录。 一&#xff0e;HTML部分 upload.html [html] view plaincopy<html> <head> &…