IO异步
一、说明
对于耗时的过程,我们将其交给别人(如其另外一个线程)去执行,而我们继续往下处理,当别人执行完耗时操作后再将结果反馈给我们,这就是我们所说的异步
二、回调写法实现原理
```python import time import threading
def long_io(callback): “”“将耗时的操作交给另一线程来处理”"" def fun(cb): # 回调函数作为参数 “”“耗时操作”"" print(“开始执行IO操作”) time.sleep(5) print(“完成IO操作,并执行回调函数”) cb(“io result”) # 执行回调函数 threading.Thread(target=fun, args=(callback,)).start() # 开启线程执行耗时操作
def on_finish(ret): “”“回调函数”"" print(“开始执行回调函数on_finish”) print(“ret: %s” % ret) print(“完成执行回调函数on_finish”)
def req_a(): print(“开始处理请求req_a”) long_io(on_finish) print(“离开处理请求req_a”)
def req_b(): print(“开始处理请求req_b”) time.sleep(2) # 添加此句来突出显示程序执行的过程 print(“完成处理请求req_b”)
def main(): req_a() req_b()
if name == ‘main’: main()
执行过程:
开始处理请求req_a 开始执行IO操作 离开处理请求req_a 开始处理请求req_b 完成处理请求req_b 完成IO操作,并执行回调函数 开始执行回调函数on_finish ret: io result 完成执行回调函数on_finish
说明:异步的特点是程序存在多个步调,即本属于同一个过程的代码可能在不同的步调上同时执行
三、协程写法实现原理
说明
在使用回调函数写异步程序时,需将本属于一个执行逻辑(处理请求a)的代码拆分成两个函数req_a和on_finish,这与同步程序的写法相差很大。而同步程序更便于理解业务逻辑,所以我们能否用同步代码的写法来编写异步程序
初始版本
<span class="hljs-keyword">import</span> time
<span class="hljs-keyword">import</span> threading
gen = <span class="hljs-keyword">None</span> <span class="hljs-comment"># 全局生成器,供long_io使用</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">long_io</span><span class="hljs-params">()</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fun</span><span class="hljs-params">()</span>:</span>
print(<span class="hljs-string">"开始执行IO操作"</span>)
<span class="hljs-keyword">global</span> gen
time.sleep(<span class="hljs-number">5</span>)
<span class="hljs-keyword">try</span>:
print(<span class="hljs-string">"完成IO操作,并send结果唤醒挂起程序继续执行"</span>)
gen.send(<span class="hljs-string">"io result"</span>) <span class="hljs-comment"># 使用send返回结果并唤醒程序继续执行</span>
<span class="hljs-keyword">except</span> StopIteration: <span class="hljs-comment"># 捕获生成器完成迭代,防止程序退出</span>
<span class="hljs-keyword">pass</span>
threading.Thread(target=fun).start()
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">req_a</span><span class="hljs-params">()</span>:</span>
print(<span class="hljs-string">"开始处理请求req_a"</span>)
ret = <span class="hljs-keyword">yield</span> long_io()
print(<span class="hljs-string">"ret: %s"</span> % ret)
print(<span class="hljs-string">"完成处理请求req_a"</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">req_b</span><span class="hljs-params">()</span>:</span>
print(<span class="hljs-string">"开始处理请求req_b"</span>)
time.sleep(<span class="hljs-number">2</span>)
print(<span class="hljs-string">"完成处理请求req_b"</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>:</span>
<span class="hljs-keyword">global</span> gen
gen = req_a()
next(gen) <span class="hljs-comment"># 开启生成器req_a的执行</span>
req_b()
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
main()
执行过程:
开始处理请求req_a
开始执行IO操作
开始处理请求req_b
完成处理请求req_b
完成IO操作,并send结果唤醒挂起程序继续执行
ret: io result
完成处理请求req_a
升级版本
说明:我们在上面编写出的版本虽然req_a的编写方式很类似与同步代码,但是在main中调用req_a的时候却不能将其简单的视为普通函数,而是需要作为生成器对待
<span class="hljs-keyword">import</span> time
<span class="hljs-keyword">import</span> threading
gen = <span class="hljs-keyword">None</span> <span class="hljs-comment"># 全局生成器,供long_io使用</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">gen_coroutine</span><span class="hljs-params">(f)</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrapper</span><span class="hljs-params">(*args, **kwargs)</span>:</span>
<span class="hljs-keyword">global</span> gen
gen = f()
next(gen)
<span class="hljs-keyword">return</span> wrapper
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">long_io</span><span class="hljs-params">()</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fun</span><span class="hljs-params">()</span>:</span>
print(<span class="hljs-string">"开始执行IO操作"</span>)
<span class="hljs-keyword">global</span> gen
time.sleep(<span class="hljs-number">5</span>)
<span class="hljs-keyword">try</span>:
print(<span class="hljs-string">"完成IO操作,并send结果唤醒挂起程序继续执行"</span>)
gen.send(<span class="hljs-string">"io result"</span>) <span class="hljs-comment"># 使用send返回结果并唤醒程序继续执行</span>
<span class="hljs-keyword">except</span> StopIteration: <span class="hljs-comment"># 捕获生成器完成迭代,防止程序退出</span>
<span class="hljs-keyword">pass</span>
threading.Thread(target=fun).start()
<span class="hljs-meta">@gen_coroutine</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">req_a</span><span class="hljs-params">()</span>:</span>
print(<span class="hljs-string">"开始处理请求req_a"</span>)
ret = <span class="hljs-keyword">yield</span> long_io()
print(<span class="hljs-string">"ret: %s"</span> % ret)
print(<span class="hljs-string">"完成处理请求req_a"</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">req_b</span><span class="hljs-params">()</span>:</span>
print(<span class="hljs-string">"开始处理请求req_b"</span>)
time.sleep(<span class="hljs-number">2</span>)
print(<span class="hljs-string">"完成处理请求req_b"</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>:</span>
req_a()
req_b()
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
main()
执行过程:
开始处理请求req_a
开始执行IO操作
开始处理请求req_b
完成处理请求req_b
完成IO操作,并send结果唤醒挂起程序继续执行
ret: io result
完成处理请求req_a
最终版本
<span class="hljs-keyword">import</span> time
<span class="hljs-keyword">import</span> threading
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">gen_coroutine</span><span class="hljs-params">(f)</span>:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">wrapper</span><span class="hljs-params">(*args, **kwargs)</span>:</span>
gen_f = f() <span class="hljs-comment"># gen_f为生成器req_a</span>
r = next(gen_f) <span class="hljs-comment"># r为生成器long_io</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fun</span><span class="hljs-params">(g)</span>:</span>
ret = next(g) <span class="hljs-comment"># 执行生成器long_io</span>
<span class="hljs-keyword">try</span>:
gen_f.send(ret) <span class="hljs-comment"># 将结果返回给req_a并使其继续执行</span>
<span class="hljs-keyword">except</span> StopIteration:
<span class="hljs-keyword">pass</span>
threading.Thread(target=fun, args=(r,)).start()
<span class="hljs-keyword">return</span> wrapper
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">long_io</span><span class="hljs-params">()</span>:</span>
print(<span class="hljs-string">"开始执行IO操作"</span>)
time.sleep(<span class="hljs-number">5</span>)
print(<span class="hljs-string">"完成IO操作,yield回操作结果"</span>)
<span class="hljs-keyword">yield</span> <span class="hljs-string">"io result"</span>
<span class="hljs-meta">@gen_coroutine</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">req_a</span><span class="hljs-params">()</span>:</span>
print(<span class="hljs-string">"开始处理请求req_a"</span>)
ret = <span class="hljs-keyword">yield</span> long_io()
print(<span class="hljs-string">"ret: %s"</span> % ret)
print(<span class="hljs-string">"完成处理请求req_a"</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">req_b</span><span class="hljs-params">()</span>:</span>
print(<span class="hljs-string">"开始处理请求req_b"</span>)
time.sleep(<span class="hljs-number">2</span>)
print(<span class="hljs-string">"完成处理请求req_b"</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span><span class="hljs-params">()</span>:</span>
req_a()
req_b()
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
main()
执行过程:
开始处理请求req_a
开始执行IO操作
开始处理请求req_b
完成处理请求req_b
完成IO操作,yield回操作结果
ret: io result
完成处理请求req_a
说明:这个最终版本就是理解Tornado异步编程原理的最简易模型,但是,Tornado实现异步的机制不是线程,而是epoll,即将异步过程交给epoll执行并进行监视回调
相关文章
- IO多路复用中select、poll、epoll之间的区别
- IO流的分类_io流的作用
- 1.2w+字!Java IO 基础知识总结
- github.io出现的问题及解决方案
- 开心档之Java 流(Stream)、文件(File)和IO
- 为什么大家都用三极管来配合单片机IO口驱动负载
- 【Netty】IO 模型简介 ( Netty 特点 | Netty 应用场景 | Java 三种 IO 模型 | BIO 模型 )
- 新一代异步IO框架 io_uring | 得物技术
- python-异常处理和错误调试-异步IO程序的调试方法(一)
- MySQL Error number: 3021; Symbol: ER_SLAVE_CHANNEL_IO_THREAD_MUST_STOP; SQLSTATE: HY000 报错 故障修复 远程处理
- 一次磁盘IO过高分析过程详解程序员
- 泛函编程(32)-泛函IO:IO Monad详解编程语言
- Linux 监控磁盘IO:快速找出瓶颈(linux监控磁盘io)
- Oracle 参数 DISK_ASYNCH_IO 官方解释,作用,如何配置最优化建议
- MySQL异步IO提高数据库性能(mysql异步io)
- Linux IO性能监控实践(监控linuxio)
- Linux查看进程IO性能分析(linux查看进程io)
- 调优提高Linux性能的IO与内存调优方法(Linuxio内存)
- 利用iostat精准监控Linux系统IO性能(iostatlinux)
- 性能优化Linux硬盘IO性能优化之路(linux硬盘io)
- 优化Linux进程IO优化:磁盘操作提速(linux进程磁盘io)
- 状态Linux下查看IO状态的简单方法(linux如何查看io)
- Linux文件IO操作指南(linux文件io)
- Linux 下的 I/O 操作——介绍(io.hlinux)
- Linux异步I/O:提升系统性能的神器(linux异步io)
- 异步IOLinux异步IO之libaio使用介绍(libaiolinux)
- Linux网络IO检测:高效识别网络状态(linux 网络io查看)
- Linux磁盘IO查看方法详解,了解磁盘性能瓶颈,提高工作效率(查看linux磁盘io)
- Oracle关闭后的异步IO踩过的坑与总结(oracle关闭异步io)
- 满Oracle IO队列满处理策略与建议(oracle出现io队列)
- Oracle IO效率之高,超凡尽致(oracle io非常高)
- Oracle IO标准最佳实践与性能突破(oracle io标准)