python网络编程 day35 网络编程——进程池,线程池、协程、回调函数、gevent模块、asyncio模块

摘要:
一、内容回顾面试题:请聊聊进程队列的特点和实现原理进程之间可以互相通信IPC数据安全先进先出实现原理管道+锁管道是基于文件级别的socket+pickle实现的你了解生产者消费者模型吗?

一、内容回顾

面试题:

  • 请聊聊进程队列的特点和实现原理

    • 进程之间可以互相通信 IPC

    • 数据安全

    • 先进先出

    • 实现原理

      • 管道+锁

      • 管道是基于文件级别的socket+pickle实现的

  • 你了解生产者消费者模型吗?

    • 了解

    • 为什么了解?

      • 工作经历:

      • 采集图片,爬取音乐,主要是爬取大量数据,想提高爬虫效率,有用过一个生产者消费者模型,这个模型使用的是消息中间件,用的是redis,获取网页的过程作为生产者,分析与获取歌曲作为消费者

    • 在python中实现生产者消费者模型可以用那些机制

      • 消息中间件

      • celery:定时发送短信的任务

  • 从你的角度说说进程在计算机中扮演什么角色

    • 资源分配的最小单位

    • 进程与进程之间内存隔离

    • 进程是由操作系统负责调度,并且进程与进程之间是竞争关系

    • 我们对进程的三状态时刻关注,因此尽量减少IO操作,或者在进程内开线程来规避IO

    • 让我们写的程序在运行时,能够更多的占用CPU资源

  • 为什么线程之间数据不安全

    • 线程之间数据共享

    • 多线程的情况下:

      • 如果在计算某一个变量时,还要进行赋值操作,这个过程不是由一条完整的CPU指令完成的,

      • 如果在判断某一个bool表达式时,再做某些操作,这个过程也不是由一条完整的CPU指令完成的,

      • 在中间发生了GIL锁的切换或时间片的轮转,可能导致数据不安全

  • 守护线程

    • 守护线程会等待主线程(包括其他子线程)结束之后才结束

    • 守护线程的结束原理,主进程结束之后,守护线程和其他所有线程资源一起被回收掉

  • 线程锁——最好只创建一把锁,线程锁一定锁不了进程

    • 互斥锁:

      • 在同一个线程中,不能连续被acquire多次,一次acquire必须对应一次release

      • 效率高

    • 递归锁

      • 在同一个线程中,可以被连续acquire多次,但一个aquire对应一个release

      • 效率低

    • 死锁现象:

      • 多把锁交替使用,在第一把锁未release释放之前已经被acqiure了

        lock.acquire()

        lock.acquire()

      • 如何解决:

        • 最快的解决办法是:把所有的互斥锁修改成递归锁,影响效率

        • 后期在慢慢整理,把递归锁能解决的问题用互斥锁处理

    • 判断数据是否安全

      • 是否数据共享,是同步还是异步,(数据共享且异步)

      • +=,-=,*=,/=计算之后,数据不安全

      • if while条件这两个判断由多个线程完成,数据不安全

  • 队列queue

    • 线程队列

      • 数据安全

      • 先进先出

      • 原理:加锁+链表

      • 先进先出的队列 Queue

      • 后进先出的队列 FILOQueue 栈

      • 优先级队列priorityQueue 根据放入数据的ascii码从小到大输出

二、今日内容

1、池 (重要)

  • 线程池

    • 一般更具IO的比例定制

    • 个数:cpu_count * 5

    #线程池
    from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
    from threading import current_thread
    import time
    import random
    import os
    def func():
    print(current_thread().ident,'开始')
    time.sleep(random.randint(1,4))
    print(current_thread().ident,'end')

    tp = ThreadPoolExecutor(3) #创建一个池,内部存在三个线程
    for i in range(20):
    tp.submit(func) #提交线程任务
  • 进程池

    • 高计算(没有IO操作,没有文件操作,没有网络操作,没有input)

    • 个数:cup_count * 1 < cup_count * 2

#进程池
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from threading import current_thread
import time
import random
import os
def func():
print(os.getpid(),'开始')
time.sleep(random.randint(1,4))
print(os.getpid(),'end')

if __name__ == '__main__':
tp = ProcessPoolExecutor(3)
for i in range(20):
tp.submit(func)
  • 函数有返回值

    #有返回值
    from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
    from threading import current_thread
    import time
    import random
    import os
    def func(i):
    print(current_thread().ident,'开始')
    time.sleep(random.randint(1,4))
    print(current_thread().ident,'end')
    return i * (i+1)
    tp = ThreadPoolExecutor(3)
    tp_lst = []
    for i in range(20):
    ret = tp.submit(func,i) #异步非阻塞
    tp_lst.append(ret)
    for ret in tp_lst:
    print(ret.result()) #获取函数的返回结果 #同步阻塞
  • 使用回调函数 效率最高

    from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
    from threading import current_thread
    import time
    import random
    import os
    def func(i):
    print(current_thread().ident,'开始')
    time.sleep(random.randint(1,4))
    print(current_thread().ident,'end')
    return i * (i+1)
    def get_result(ret):
    print(ret.result())
    tp = ThreadPoolExecutor(3)
    for i in range(20):
    ret = tp.submit(func,i)
    ret.add_done_callback(get_result) #异步阻塞

2、协程

  • 协程概念(非常重要)

    • 是操作系统不可见的

    • 协程本质就是一条线程,多个任务在一条线程上来回切换,来规避IO操作,就达到我们将一条线程中的io操作降到最低

    • 模块 规避io的两个模块

      • gevent 利用了 greenlet 底层模块完成的切换—自动规避io的功能

      • asyncio 利用了 yield 底层语法完成的切换—自动规避io的功能

    • 1611629278250

  • gevent 第三方模块

    • 会用

    • 能处理一些基础的网络操作

      from gevent import monkey
      monkey.patch_all()
      import gevent
      import time
      import random
      def func(i):
      print('start:',i)
      time.sleep(random.randint(1,4))
      print('end:',i)
      g = gevent.spawn(func,1)
      g1 = gevent.spawn(func,1)
      g2 = gevent.spawn(func,1)
      gevent.joinall([g,g1,g2])
  • asyncio 内置模块

    import asyncio
    async def func(i):
    print('start:', i)
    await asyncio.sleep(2)
    print('end:', i)

    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait([func(1),func(3)]))
3、区别
  • 进程:计算机资源分配的最小单位 数据不安全 开销大 可以利用多核 操作系统级别

  • 线程 计算机(cpu)调度的最小单位 数据不安全 开销小 不能利用多核 操作系统级别

  • 协程 计算机(cpu)调度的最小单位 数据安全 更小 不能利用多核 用户级别

免责声明:文章转载自《python网络编程 day35 网络编程——进程池,线程池、协程、回调函数、gevent模块、asyncio模块》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇一种用buildkit打造免registry的local cd/ci工具,打通vscodeonline与openfaas模拟cloudbase打造碎片化编程开发部署环境的设想day43_MySql下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

北洋大讲堂之“斯凯网络CEO宋涛我的创业之路”感想

最近听到的看到的关于创业的消息比较多,先后有两个朋友辞去了一家创业公司的工作开始专心做自己的事情,在微信上也在读关于创业的《失业的程序员》连载,正好今天又听了96级校友宋涛先生的精彩报告,写下来一些东西记录关于创业的一些思考。 尤其在IT行业,创业公司遍地开花,北京之类的大城市创业氛围也比较浓,这里的人们大多有技术、有想法,也有一定的人脉,都很想发挥自己更大...

《Python》并发编程

手工操作 —— 穿孔卡片       1946年第一台计算机诞生--20世纪50年代中期,计算机工作还在采用手工操作方式。此时还没有操作系统的概念。             程序员将对应于程序和数据的已穿孔的纸带(或卡片)装入输入机,然后启动输入机把程序和数据输入计算机内存,接着通过控制台开关启动程序针对数据运行;计算完毕,打印机输出计算结果;用户取走结果...

Tomcat性能调优及性能测试工具配置

前言 运行环境:Ubuntu server14 64位 Jdk版本:jdk-1.7.0_79 Tomcat版本:apache-tomcat-7.0.63 Tomcat性能调优 1、 内存优化 修改tomcat/bin目录下catalina.sh文件: JAVA_OPTS=”$JAVA_OPTS -Dfile.encoding=utf-8 -serve...

Android 4 学习(19):Services

参考《Professional Android 4 Development》   Services Service是invisible的,因此其优先级不高于visible的Activity,之所以说不高于,是因为我们可以设置Service为在前台运行。 创建Service Android提供了Service抽象类,继承它便可以创建一个Service类:  ...

unity 协程与async、await

协程(Coroutine) 协程就像一个函数,能够暂停执行并将控制权返还给 Unity,然后在指定的时间继续执行。协程本质上是一个用返回类型 IEnumerator 声明的函数,并在主体中的某个位置包含 yield return 语句。yield return 是暂停执行并随后在下一个时间点恢复。注意:Fade 函数中的循环计数器能够在协程的生命周期内保持...

《Win32多线程程序设计》学习笔记 第10章 MFC 中的线程

如果要在MFC程序中产生一个线程,而该线程将调用MFC函数或者使用MFC的任何数据,那么你必须以AfxBeginThread()或者CWinThread::CreateThread()来产生这些线程,理由同C runtime library. 在MFC中启动一个worker线程 如果线程调用了GetMessage或者CreateWindow之类的函数,消息...