热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Python编程中的并发与并行:深入解析阻塞、非阻塞、同步、异步及IO多路复用技术

在Python编程中,探讨了并发与并行的概念及其区别。并发指的是系统同时处理多个任务的能力,而并行则指在同一时间点上并行执行多个任务。文章详细解析了阻塞与非阻塞操作、同步与异步编程模型,以及IO多路复用技术的应用。通过模拟socket发送HTTP请求的过程,展示了如何创建连接、发送数据和接收响应,并强调了默认情况下socket的阻塞特性。此外,还介绍了如何利用这些技术优化网络通信性能和提高程序效率。

一、并发并行

并发:表示执行多个任务的能力

并行:表示同一时刻执行多个任务

二、模拟socket发送http请求

三大步骤:创建连接 要发送的东西 然后数据回来接收    socket默认情况下阻塞

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 import socket
 5 
 6 client = socket.socket()
 7 client.setblocking(False)  # 这里设置非阻塞  
 8 # 百度创建连接:阻塞
 9 try:
10     client.connect((www.baidu.com, 80))  # 执行了但报错
11 except BlockingIOError as e:
12     pass
13 
14 # 发送要东西了
15 client.sendall(bGET /s?wd=hello HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n)
16 
17 # 百度给我的回复
18 chunk_list = []
19 while True:
20     try:
21         # 阻塞
22         chunk = client.recv(8096)
23         if not chunk:
24             break
25         chunk_list.append(chunk)
26     except BlockingIOError:
27         pass
28 
29 print(b‘‘.join(chunk_list).decode(utf8))

 三、基于单线程和IO多路复用发送多个任务(并发方法一非阻塞)

IO多路复用作用:只是检测socket的变化 是否连接成功 是否返回数据 是否可读可写

rlist, wlist, elist = select.select(socket_list, conn_list, [], 0.005)  

conn_list   检测其中所有socket对象是否与服务器连接成功   可写
socket_list 检测服务器是否有数据给我返回来 可读
[]    检测是否有错误
    连接最大超出的时间为0.005秒
rlist 返回数据的放在rlist中
wlist 把连接成功的放在wlist列表中 

实现的方式有两种   

select.select(socket_list, conn_list, [], 0.005)
select监听的socket_list, conn_list内部会调用列表中的每一个值得fileno方法,获取该返回值并去系统中检测
方式一:
select.select([client1, client2], [client1, client2], [], 0.005)
方式二:高级版本 封装socket对象
select.select([Foo(client1), Foo(client2)], [Foo(client1), Foo(client2)], [], 0.005)

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 import socket
 5 import select
 6 
 7 client1 = socket.socket()
 8 client1.setblocking(False)
 9 try:
10     client1.connect(("www.baidu.com", 80))
11 except BlockingIOError as e:
12     pass
13 
14 client2 = socket.socket()
15 client2.setblocking(False)
16 try:
17     client2.connect(("www.so.com", 80))
18 except BlockingIOError as e:
19     pass
20 socket_list = [client1, client2]
21 conn_list = [client1, client2]
22 while True:
23     rlist, wlist, elist = select.select(socket_list, conn_list, [], 0.005)
24     for sk in wlist:
25         if sk == client1:
26             sk.sendall(bGET /s?wd=hello HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n)
27         else:
28             sk.sendall(bGET /s?q=hello HTTP/1.0\r\nhost:www.so.com\r\n\r\n)
29         conn_list.remove(sk)
30 
31     for sk in rlist:
32         chunk_list = []
33         while True:
34             try:
35                 chunk = sk.recv(8096)
36                 if not chunk:
37                     break
38                 chunk_list.append(chunk)
39             except BlockingIOError as e:
40                 break
41         body = b"".join(chunk_list)
42         print("----->", body.decode(utf8))
43         # print("----->", body)
44         sk.close()
45         socket_list.remove(sk)
46     if not socket_list:
47         break
48 
49 """
50 回调:异步本质(通知)
51 def callback(arg):
52     print(arg)
53 func("www.baidu.com/s?wd=hello" callback)
54 print(123)
55 print(123)
56 print(123)
57 """

 四、利用单线程实现高并发NB高级版本(高并发方法二异步非阻塞)

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 import socket
 5 import select
 6 
 7 
 8 class Req(object):
 9     def __init__(self, sk, func):
10         self.sock = sk
11         self.func = func
12 
13     def fileno(self):
14         return self.sock.fileno()
15 
16 
17 class Nb(object):
18 
19     def __init__(self):
20         self.conn_list = []
21         self.socket_list = []
22 
23     def add(self, url, func):
24         client = socket.socket()
25         client.setblocking(False)  
26         try:
27             client.connect((url, 80))
28         except BlockingIOError as e:
29             pass
30         obj = Req(client, func)
31         self.conn_list.append(obj)
32         self.socket_list.append(obj)
33 
34     def run(self):
35         while True:
36             rlist, wlist, elist = select.select(self.socket_list, self.conn_list, [], 0.005)
37             for sk in wlist:
38                 sk.sock.sendall(bGET /s?wd=hello HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n)
39                 self.conn_list.remove(sk)
40 
41             for sk in rlist:
42                 chunk_list = []
43                 while True:
44                     try:
45                         chunk = sk.sock.recv(8096)
46                         if not chunk:
47                             break
48                         chunk_list.append(chunk)
49                     except BlockingIOError as e:
50                         break
51                 body = b"".join(chunk_list)
52                 sk.func(body)
53                 sk.sock.close()
54                 self.socket_list.remove(sk)
55             if not self.socket_list:
56                 break
57 
58 
59 def baidu_response(body):
60     print(百度下载的结果, body)
61 
62 
63 def sogou_response(body):
64     print(搜狗下载的结果, body)
65 
66 
67 t1 = Nb()
68 t1.add(www.baidu.com, baidu_response)
69 t1.add(www.so.com, sogou_response)
70 t1.run()

 总结:

IO多路复用的作用: 检测多个socket是否发生变化
操作系统检测socket是否发生变化 有三种模式
select:最多1024个socket个数 循环去检测。
poll: 不限制监听socket个数,循环去检测。(水平触发)
epoll: 不限制监听socket个数,回调的方式(边缘触发) windows下没有 触发的机制可以采用简单点儿的高低电平来理解
    linux下
select.epoll 有点复杂注册哪些等等操作 用法差不多select.select
            提高并发方案:多进程 多线程 异步非阻塞模块(Twisted)
什么是异步非阻塞?
   非阻塞, 不等待 比如:创建socket对某个地址进行连接,获取接收数据时就会等待,连接成功/接收到数据时,
才执行后续操作,如果设置setblocking(False),上边两过程不再等待,但是要报错BlockingError,只要去捕获即可
异步:(通知)执行完成之后自动执行回调函数或者自动执行某些操作(通知)最根本就是执行完某个任务自动调用我给他的函数
比如:爬虫中向某个地址发送请求,当请求执行完成之后自动执行回调函数

什么是同步阻塞?
同步:按照顺序逐步执行
阻塞:等待

    这么多代码其实可以不用写 基于异步非阻塞的框架 基于事件循环(驱动) Twisted

 

Python之并发、并行、阻塞、非租塞、同步、异步、IO多路复用


推荐阅读
  • 在处理大规模并发请求时,传统的多线程或多进程模型往往无法有效解决性能瓶颈问题。尽管它们在处理小规模任务时能提升效率,但在高并发场景下,系统资源的过度消耗和上下文切换的开销会显著降低整体性能。相比之下,Python 的 `asyncio` 模块通过协程提供了一种轻量级且高效的并发解决方案。本文将深入解析 `asyncio` 模块的原理及其在实际应用中的优化技巧,帮助开发者更好地利用协程技术提升程序性能。 ... [详细]
  • 在基于.NET框架的分层架构实践中,为了实现各层之间的松散耦合,本文详细探讨了依赖注入(DI)和控制反转(IoC)容器的设计与实现。通过合理的依赖管理和对象创建,确保了各层之间的单向调用关系,从而提高了系统的可维护性和扩展性。此外,文章还介绍了几种常见的IoC容器实现方式及其应用场景,为开发者提供了实用的参考。 ... [详细]
  • C#中实现高效UDP数据传输技术
    C#中实现高效UDP数据传输技术 ... [详细]
  • 高效批量文件重命名软件
    开发了一款基于Python的高效批量文件重命名软件,并集成了wxWidgets图形用户界面,使用cxfreeze将其打包为独立的可执行文件(exe)。该工具适用于需要频繁处理大量文件的用户,能够显著提高文件管理效率。详细使用说明包含在软件压缩包内。开发环境为Python 2.7和wxWidgets 3.0,运行环境要求兼容Windows系统。 ... [详细]
  • 在第六章中,我们将深入探讨MySQL中的多表查询技术,包括联结查询和子查询。联结查询通过将两个或多个表进行连接,基于连接条件生成结果集。常见的联结类型有内联结、外联结和全外联结。交叉联结(CROSS JOIN)虽然使用较少,但其原理是生成所有可能的组合,类似于笛卡尔积的概念。此外,子查询则是在一个查询语句中嵌套另一个查询,用于获取更复杂的数据集。本章将通过实例详细讲解这些查询方法的应用和优化技巧。 ... [详细]
  • 本文深入探讨了 iOS 开发中 `int`、`NSInteger`、`NSUInteger` 和 `NSNumber` 的应用与区别。首先,我们将详细介绍 `NSNumber` 类型,该类用于封装基本数据类型,如整数、浮点数等,使其能够在 Objective-C 的集合类中使用。通过分析这些类型的特性和应用场景,帮助开发者更好地理解和选择合适的数据类型,提高代码的健壮性和可维护性。苹果官方文档提供了更多详细信息,可供进一步参考。 ... [详细]
  • 解决基于XML配置的MyBatis在Spring整合中出现“无效绑定语句(未找到):com.music.dao.MusicDao.findAll”问题的方法
    在将Spring与MyBatis进行整合时,作者遇到了“无效绑定语句(未找到):com.music.dao.MusicDao.findAll”的问题。该问题主要出现在使用XML文件配置DAO层的情况下,而注解方式配置则未出现类似问题。作者详细分析了两个配置文件之间的差异,并最终找到了解决方案。本文将详细介绍问题的原因及解决方法,帮助读者避免类似问题的发生。 ... [详细]
  • Python学习:环境配置与安装指南
    Python作为一种跨平台的编程语言,适用于Windows、Linux和macOS等多种操作系统。为了确保本地已成功安装Python,用户可以通过终端或命令行界面输入`python`或`python3`命令进行验证。此外,建议使用虚拟环境管理工具如`venv`或`conda`,以便更好地隔离不同项目依赖,提高开发效率。 ... [详细]
  • 本课程详细介绍了如何使用Python Flask框架从零开始构建鱼书应用,涵盖高级编程技巧和实战项目。通过视频教学,学员将学习到Flask的高效用法,包括数据库事务处理和书籍交易模型的实现。特别感谢AI资源网提供的课程下载支持。 ... [详细]
  • 使用Boost.Asio进行异步数据处理的应用程序主要依赖于两个核心概念:I/O服务和I/O对象。I/O服务抽象了操作系统接口,使得异步操作能够高效地执行。I/O对象则代表了具体的网络资源,如套接字和文件描述符,通过这些对象可以实现数据的读写操作。本文详细介绍了这两个概念在Boost.Asio中的应用及其在网络编程中的重要性。 ... [详细]
  • Select2.js下拉框应用总结与实践要点
    在使用Select2.js下拉框插件的过程中,积累了诸多实践经验与心得。尽管最初觉得Select2在某些方面不尽如人意,但在对比了其他选项后,发现其仍是最优选择。本文将详细探讨Select2.js的配置、优化技巧及常见问题解决方法,帮助开发者更好地利用这一强大的前端工具。 ... [详细]
  • 本文详细解析了JSONP(JSON with Padding)的跨域机制及其工作原理。JSONP是一种通过动态创建``标签来实现跨域请求的技术,其核心在于利用了浏览器对``标签的宽松同源策略。文章不仅介绍了JSONP的产生背景,还深入探讨了其具体实现过程,包括如何构造请求、服务器端如何响应以及客户端如何处理返回的数据。此外,还分析了JSONP的优势和局限性,帮助读者全面理解这一技术在现代Web开发中的应用。 ... [详细]
  • voc生成xml 代码
    目录 lxmlwindows安装 读取示例 可视化 生成示例 上面是代码,下面有调用示例 api调用代码,其实只有几行:这个生成代码也很简 ... [详细]
  • 利用ViewComponents在Asp.Net Core中构建高效分页组件
    通过运用 ViewComponents 技术,在 Asp.Net Core 中实现了高效的分页组件开发。本文详细介绍了如何通过创建 `PaginationViewComponent` 类并利用 `HelloWorld.DataContext` 上下文,实现对分页参数的定义与管理,从而提升 Web 应用程序的性能和用户体验。 ... [详细]
  • 在操作系统中,阻塞状态与挂起状态有着显著的区别。阻塞状态通常是指进程因等待某一事件(如I/O操作完成)而暂时停止执行,而挂起状态则是指进程被系统暂时移出内存,以释放资源或降低系统负载。此外,本文还深入分析了`sleep()`函数的实现机制,探讨了其在不同操作系统中的具体实现方式及其对进程调度的影响。通过这些分析,读者可以更好地理解操作系统如何管理进程的不同状态以及`sleep()`函数在其中的作用。 ... [详细]
author-avatar
莫名其妙520a_416
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有