Python之路 - 多进程实例及回调函数
进程池实例 🍀
使用进程池维护固定数目的进程
server.py
1 | import socket |
client.py
1 | import socket |
使用进程池维护固定数目的进程
server.py
1 | import socket |
client.py
1 | import socket |
在网络编程中 , 如果服务端需要面临同时接收上千甚至上万次的客户端请求 , 利用 “进程池” 或 “线程池” 或许可以缓解部分压力 , 但是并不是一个好的选择 , 因为超过数量还是得等 ; 又或者线程一旦进行堵塞 ; 以及任务之间的高度独立 , 并不需要互相通信或者等待时 , 我们就需要用到I/O多路复用(IO Multiplexing) 了 , 又叫做事件驱动IO (Event driven IO)
I/O多路复用是指单个线程中 , 通过记录跟踪每个I/O流(sock)的状态 , 来同时管理多个I/O流
在I/O多路复用中只要一遇到IO就注册一个事件 , 然后主程序就可以继续干其他的事情了 , 直到IO处理完毕 , 继续恢复之前中断的任务 , 也就是说一个线程可以同时处理多个请求
举🌰
在UI编程中 , 常常要对鼠标点击进行响应 , 还要同时对键盘敲击也进行响应
多进程多线程方式 :
创建一个进程 , 进程中有两个线程 , 一个循环检测鼠标点击 , 一个循环检测键盘敲击 , 一旦检测到有情况就再开一个线程去处理 , 然后一直开下去……基本上是由创建进程/线程 , 维护进程/线程来解决的 , 这样对于CPU的资源是很浪费的
IO多路复用(事件驱动) :
创建一个事件(消息)队列 , 鼠标点击就往队列中增加一个鼠标点击事件 , 键盘敲击就往队列中增加一个键盘敲击事件 , 创建一个线程(IO线程)负责不断从队列中取出事件 , 根据不同的事件 , 调用不同的函数 , 如onClick() , onKeyDown()等 , 即一个线程解决了所有事件的问题 , 这就是复用
比较 : 与多进程多线程技术相比 , I/O多路复用最大的优势是系统开销小 , 系统不必创建进程/线程 , 也不必维护这些进程/线程 , 从而大大减小了系统的开销
目前常见支持I/O多路复用的系统调用select , poll , epoll ,I/O多路复用就是通过一种机制 , 一个进程可以监视多个描述符 , 一旦某个描述符就绪(一般是读就绪或者写就绪) , 能够通知程序进行相应的读写操作
而I/O多路复用的具体实现就是 , select , poll , epoll
在前面的文章中 , 基本已经可以解决并发编程中的基本问题了 , 但是如果我们要利用单线程来实现并发 , 线程是轻量级的进程 , 为了使计算机资源能更充分的利用 , 那么我们就需要用到协程了
并发的本质就是上下文切换加上保存状态 , 那么我们就可以想到关键字yield
, 我们在生成器篇章中 , 就是利用了yield
实现了状态的保存 , 来看一个廖大大的例子
生产者消费者模型yield版
1 | import time |
上述例子中yield
确实实现了并发 , 但是并没有实现遇到IO操作进行自动切换 , 所以协程出场了
1 | import Queue |
函数是组织好的 , 可重复使用的 , 用来实现单一 , 或相关联功能的代码段
函数能提高应用的模块性 , 和代码的重复利用率 , 比如我们一直使用的print()
, input()
等等 , 都是函数
如下我们写了一个用户认证程序 ; 而现在我们又需要写一个用户管理系统 , 管理系统中有很多的功能 , 比如添加用户 , 删除用户 , 查询用户 , 修改用户 ; 但是这些功能必须先通过用户认证程序才能使用 , 明显我们不可能在每一个功能前加上一段用户认证代码 , 因为这将大大增加我们的重复代码
那么为了解决这个问题我们就可以将用户认证功能封装到一个函数之中 , 而后续我们如果需要使用这个函数仅需调用即可 , 着就是函数的魅力所在 , 当然更多的还是通过下面进一步了解函数
1 | # 自定义函数,function_name为函数名 |
嵌套函数即函数里面再套一个函数 , 如下 :
1 | # 全局变量name |
exec
(object[, globals[, locals]]) 👈
将字符串当做表达式去执行,没有返回值
1 | # 流程语句用exec |
eval
(expression, globals=None, locals=None) 👈
将字符串当做表达式去执行,并返回执行结果
1 | # 简单求值表达式用eval |
compile
(source, filename, mode, flags=0, dont_inherit=False, optimize=-1) 👈
在Python中一切皆对象
迭代是重复反馈过程的活动 , 其目的通常是为了逼近所需目标或结果
可迭代对象 , 即可以按照迭代的方式进行存取数据的对象 , 在python中我们可以理解为可以用for循环遍历的对象就是可迭代对象
for循环做的那些事 : for循环是我们用来遍历一个数据集合的方法 , 其实就是根据一定的要求 (这个要求叫做’协议’ ) 进行一次次的迭代的效果 . 当我们用for循环去遍历时 , 它做的第一件事就是判断对象是否是可迭代对象 , 如果是 , 那么它就会将该对象转换成一个迭代器 , 最后利用__next__()
方法将迭代器中的内容一个接一个的取出来
可迭代对象的标志是 , 它具有__iter__()
方法
判断对象是否为可迭代对象方法如下:
1 | # 导入模块 |
递归算法是一种直接或者间接地调用自身算法的过程(递归函数就是一个体现)。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简介而且易于理解。
特点:👈
要求:👈
lambda是一个表达式 , 而并非语句 , 所以可以出现在def语句所不能出现的位置 , 并且不需要指定函数名; lambda表达式还可以提高代码的可读性 , 简化代码
lambda表达式主要用于写一些简单的方法 , 对于复杂的还是用函数写的好
示例:
1 | # 普通函数 |