了解异步编程

楼主在工作中遇到了以下问题,开发接口爬取数据代码完成之后要写入redis缓存,但是在写入缓存的过程花费2-3s,进行这样就大大影响了接口的性能,于是想到了使用异步存储。

传统的同步编程是一种请求响应模型,调用一个方法,等待其响应返回.

异步编程就是要重新考虑是否需要响应的问题,也就是缩小需要响应的地方。因为越快获得响应,就是越同步化,顺序化,事务化,性能差化。

线程实现异步

思路:通过线程调用的方式,来达到异步非阻塞的效果,也就是说主程序无需等待线程执行完毕,仍然可以继续向下执行。

1.threading模块和thread模块

Python通过两个标准库thread和threading提供对线程的支持。thread提供了低级别的、原始的线程以及一个简单的锁。

threading 模块提供的其他方法:

threading.currentThread(): 返回当前的线程变量。

threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。

threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:

run(): 用以表示线程活动的方法。

start():启动线程活动。

join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。

isAlive(): 返回线程是否活动的。

getName(): 返回线程名。

setName(): 设置线程名。

同步阻塞:

1 import threading,time

2

3 def thead(num):

4 time.sleep(1)

5 print("阻塞程序%s开始执行"%num)

6 time.sleep(3)

7 print("阻塞程序%s执行完毕"%num)

8

9 def main():

10 print("主方法开始执行")

11

12 for i in range(1,3):

13 thead(i)

14

15 print("主方法执行完毕")

16 return

17

18 if __name__ == '__main__':

19 print(time.ctime())

20 num = main()

21 print("返回结果为%s"%num)

22 print(time.ctime())

Wed Nov 21 09:22:56 2018

主方法开始执行

阻塞程序1开始执行

阻塞程序1执行完毕

阻塞程序2开始执行

阻塞程序2执行完毕

主方法执行完毕

返回结果为None

Wed Nov 21 09:23:04 2018

异步,无需等待线程执行

import threading,time

def thead(num):

# time.sleep(1)

print("线程%s开始执行"%num)

time.sleep(3)

print("线程%s执行完毕"%num)

def main():

print("主方法开始执行")

#创建2个线程

poll = []#线程池

for i in range(1,3):

thead_one = threading.Thread(target=thead, args=(i,))

poll.append(thead_one) #线程池添加线程

for n in poll:

n.start() #准备就绪,等待cpu执行

print("主方法执行完毕")

return

if __name__ == '__main__':

print(time.ctime())

num = main()

print("返回结果为%s"%num)

print(time.ctime())

Wed Nov 21 09:48:00 2018

主方法开始执行

主方法执行完毕

返回结果为None

Wed Nov 21 09:48:00 2018

线程1开始执行

线程2开始执行

线程1执行完毕

线程2执行完毕

2.concurrent.futures模块

concurrent.futures模块实现了对threading(线程)和multiprocessing(进程)的更高级的抽象,对编写线程池/进程池提供了直接的支持。

从Python3.2开始,标准库为我们提供了concurrent.futures模块,它提供了ThreadPoolExecutor和ProcessPoolExecutor两个类,ThreadPoolExecutor和ProcessPoolExecutor继承了Executor,分别被用来创建线程池和进程池的代码。(暂时只介绍线程池的使用)

concurrent.futures模块的基础是Exectuor,Executor是一个抽象类,它不能被直接使用。但是它提供的两个子类ThreadPoolExecutor和ProcessPoolExecutor却是非常有用,顾名思义两者分别被用来创建线程池和进程池的代码。我们可以将相应的tasks直接放入线程池/进程池,不需要维护Queue来操心死锁的问题,线程池/进程池会自动帮我们调度。

Future这个概念你可以把它理解为一个在未来完成的操作,这是异步编程的基础,传统编程模式下比如我们操作queue.get的时候,在等待返回结果之前会产生阻塞,cpu不能让出来做其他事情,而Future的引入帮助我们在等待的这段时间可以完成其他的操作。

Future Objects:Future类封装了可调用的异步执行.Future 实例通过 Executor.submit()方法创建。

submit(fn, *args, **kwargs):调度可调用的fn,作为fn(args kwargs)执行,并返回一个表示可调用的执行的Future对象。

ThreadPoolExecutor:ThreadPoolExecutor是一个Executor的子类,它使用线程池来异步执行调用。

concurrent.futures.ThreadPoolExecutor(max_workers=None, thread_name_prefix=''):Executor子类,使用max_workers规格的线程池来执行异步调用。

在Flask应用中使用异步redis:

from flask import Flask

import time

from concurrent.futures import ThreadPoolExecutor

executor = ThreadPoolExecutor()

app = Flask(__name__)

@app.route('/')

def update_redis():

executor.submit(do_update)

return 'ok'

def do_update():

time.sleep(3)

print('start update cache')

time.sleep(1)

print("end")

if __name__ == '__main__':

app.run(debug=True)

“ok“在更新缓存前已经返回。

本文到这里就结束了,着重介绍了线程实现异步的方法。当然还有其他的方法,比如yied实现,还有asyncio模块,后续会继续更新异步编程的文章。

温馨提示

本文代码是在python3.5版本测试运行。

python异步线程算法应用_Python多线程----线程池以及线程实现异步任务相关推荐

  1. python守护多线程_Python多线程Threading、子线程与守护线程实例详解

    线程Threading: python中多线程需要使用threading模块 线程的创建与运行: 1.直接调用threading的Thread类: 线程的创建:线程对象=thread.Thread(t ...

  2. python线程join方法_Python多线程join()用法

    Python多线程与多进程中join()方法的效果是相同的. 下面仅以多线程为例: 首先需要明确几个概念: 知识点一:主进程结束,子进程继续执行 当一个进程启动之后,会默认产生一个主线程,因为线程是程 ...

  3. python爬取天天基金_python多线程+代理池爬取天天基金网、股票数据过程解析

    简介 提到爬虫,大部分人都会想到使用Scrapy工具,但是仅仅停留在会使用的阶段.为了增加对爬虫机制的理解,我们可以手动实现多线程的爬虫过程,同时,引入IP代理池进行基本的反爬操作. 本次使用天天基金 ...

  4. python 进程池 等待数量_【2020Python修炼记】python并发编程(六)补充—进程池和线程池...

    1. 2. 为啥要有 进程池和线程池 进程池来控制进程数目,比如httpd的进程模式,规定最小进程数和最大进程数 3.创建进程池的类pool 如果指定numprocess为3,则进程池会从无到有创建三 ...

  5. 线程和进程(1)——多线程,进程与线程

    一.为什么要用多线程 1.让计算机"同时"做多件事情,节约时间. 2.后台运行程序,提高程序的运行效率,也不会使主界面出现无响应的情况. 3.多线程可以让一个程序"同时& ...

  6. python线程只能启动一次_python多线程只能运行一个线程的问题

    问题描述: 使用 python threading.Thread() 建立两个线程,启动后只有线程1在运行,线程2不运行. 问题代码 import time, threading def run_th ...

  7. python线程间通信_python多线程之事件触发(线程间通信)

    执行结果: 那么,通过分析执行结果来看,您已经体会到了其中的秘密.... 再脑补一下: Python提供了Event对象用于线程间通信,它是由线程设置的信号标志,如果信号标志位真,则其他线程等待直到信 ...

  8. python sleep函数什么意思_Python sleep()函数用法:线程睡眠

    位于 time 模块中的 sleep(secs) 函数,可以实现令当前执行的线程暂停 secs 秒后再继续执行.所谓暂停,即令当前线程进入阻塞状态,当达到 sleep() 函数规定的时间后,再由阻塞状 ...

  9. python 全中文匹配字符_Python教程:进程和线程amp;正则表达式

    字符串是编程时涉及到的最多的一种数据结构,对字符串进行操作的需求几乎无处不在.比如判断一个字符串是否是合法的Email地址,虽然可以编程提取@前后的子串,再分别判断是否是单词和域名,但这样做不但麻烦, ...

最新文章

  1. 当支持向量机遇上神经网络......
  2. 刚刚做了个chrome浏览器 博客园转载插件,欢迎试用,多提意见!
  3. strcpy与面试官
  4. rhel5.5配置yum
  5. poj 2983 Is the Information Reliable?
  6. 学计算机还要写作文吗,第一次学电脑作文3篇
  7. tensorflow,Anaconda和 vscode 如何连接以及问题解决
  8. HTTP和WebSocket协议(二)
  9. 研发管理三部曲——贰 · 研发管理应该干什么
  10. [Codeforces Round #152 (Div. 2)]A. Cupboards
  11. 爱心宠物诊所管理系统
  12. 单片机c语言中断延时,单片机中C语言延时函数
  13. Redis面试题及答案 2021最新版 140道
  14. FFmpeg将MP4视频切割成ts文件
  15. stack的常见用法
  16. 基于树莓派的微型气象台
  17. C++经典算法题-猴子吃桃问题
  18. ubuntu安装QT5.14.2:编译项目报错、不能输入中文解决
  19. SQL Server 2016详细安装步骤,后附链接
  20. java 模拟登录微信_java 微信模拟登录错误,微信改版后不能使用

热门文章

  1. 接收机端口电压dBuV如何转化为功率dBmW
  2. cat /etc/redhat-release 查看centos版本
  3. 字符串转数组的几种方法和字符串的截取
  4. weblogic发序列化命令执行漏洞工具分享
  5. IIS上部署网站问题总结
  6. linux下安装erlang,以及cowboy的初步接触的一些环境安装
  7. JSP的优势与劣势浅析
  8. lightbox的一个ajax效果
  9. [转载] numpy.gradient
  10. Mybatis案例升级版——小案例大道理