zoukankan      html  css  js  c++  java
  • 进程池和线程池,协程,IO多路复用

    进程池、线程池:

    开进程池和线程池都是要消耗资源的,只不过比较而言消耗的资源进程池多一点,线程池少一点

    就是在计算机硬件能承受的最大范围内去利用计算机。

    什么是池?

    就是在保证计算机硬件安全的情况最大利用计算机。

    因为计算机硬件的发展跟不上软件的速度。

    作用:

    1.自动管理了进程/线程的开启和销毁

    2.自动管理分配任务

    3.限制了进程/线程的创建数量,信号量只是限制了最大并发线程访问数量,线程已经创建了。

    就是可以对线程/进程进行回收,

    池子中创建的进程/线程创建一次就不会再创建了
    从始至终使用都是那几个,这样就节省了开启线程进程的资源

    使用:

    submint()是提交任务

    pool.shutdown() # 等待所有任务全部完毕 销毁所有线程 后关闭线程池

    def task(n):
        print(n,os.getpid())  # 查看当前进程号
        time.sleep(2)
        return n**2
    
    
    def call_back(n):
        print('拿到了异步提交任务的返回结果:',n.result())
    """
    提交任务的方式
        同步:提交任务之后 原地等待任务的返回结果 期间不做任何事
        异步:提交任务之后 不等待任务的返回结果(异步的结果怎么拿???) 直接执行下一行代码
    """
    
    # pool.submit(task,1)  # 朝线程池中提交任务   异步提交
    # print('主')
    """
    异步回调机制:当异步提交的任务有返回结果之后,会自动触发回调函数的执行
    
    """
    if __name__ == '__main__':
    
        t_list = []
        for i in range(20):
            res = pool.submit(task,i).add_done_callback(call_back)  # 提交任务的时候 绑定一个回调函数 一旦该任务有结果 立刻执行对于的回调函数
            # print(res.result())  # 原地等待任务的返回结果
            t_list.append(res)
    
        # pool.shutdown()  # 关闭池子 等待池子中所有的任务执行完毕之后 才会往下运行代码
        # for p in t_list:
        #     print('>>>:',p.result())
    View Code

    协程:

    就是单线程下实现并发。

    也叫轻量级线程。

    并发:就是看上去是并行,其实是切换加保存执行

    并行:就是真正意义上的同时进行。

    IO密集用多线程

    计算密集用多进程

    首先我们可以使用生成器完成并发执行

    def task1():
        while True:
            yield
            print("task1 run")
    
    def task2():
        g = task1()
        while True:
            next(g)
            print("task2 run")
    task2()

    优点:协程的创建开销更小,属于程序级别的,操作系统完全感知不到。

       单线程下就能实现并发执行,最大限度使用cpu

    gevent模块:

    import gevent,sys
    from gevent import monkey # 导入monkey补丁
    monkey.patch_all() # 打补丁 
    import time
    
    print(sys.path)
    
    def task1():
        print("task1 run")
        # gevent.sleep(3)
        time.sleep(3)
        print("task1 over")
    
    def task2():
        print("task2 run")
        # gevent.sleep(1)
        time.sleep(1)
        print("task2 over")
    
    g1 = gevent.spawn(task1)
    g2 = gevent.spawn(task2)
    #gevent.joinall([g1,g2])
    g1.join()
    g2.join()

    如果没有join的话,执行以上代码不会有任何信息,因为协程的任务都是以异步的方式提交的,所以主线程会继续执行代码,直到运行完最后一行便会结束主进程。这就导致了协程的任务没有及时执行,所以这个时候我们要用join来保证协程内的代码执行完毕后才会执行主线程,当然如果主线程不会结束那么也就不需要调用join。

    注意:

    1.如果主线程结束了 协程任务也会立即结束。

    2.monkey补丁的原理是把原始的阻塞方法替换为修改后的非阻塞方法,即偷梁换柱,来实现IO自动切换

    必须在打补丁后再使用相应的功能,避免忘记,建议写在最上方

    IO模型:

    总共有五种IO:

    blocking IO           阻塞IO
    nonblocking IO      非阻塞IO
    IO multiplexing      IO多路复用
    signal driven IO     信号驱动IO
    asynchronous IO    异步IO

    阻塞IO:

     在linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概是这样:

    非阻塞IO:

    Linux下,可以通过设置socket使其变为non-blocking。当对一个non-blocking socket执行读操作时,流程是这个样子:

      

    IO多路复用:

    IO multiplexing这个词可能有点陌生,但是如果我说select/epoll,大概就都能明白了。有些地方也称这种IO方式为事件驱动IO(event driven IO)。我们都知道,select/epoll的好处就在于单个process就可以同时处理多个网络连接的IO。它的基本原理就是select/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。它的流程如图:

    异步IO(ASYN开头的):

    Linux下的asynchronous IO其实用得不多,从内核2.6版本才开始引入。先看一下它的流程:

  • 相关阅读:
    Java Jsoup Spider抓取数据入库
    DevOps详解
    七款做好DevOps的强大工具
    DevOps 初学者的入门指南
    DevOps必备的20款顶级工具
    Docker 三大核心工具
    Deploying Docker images via SSH
    Shell实现判断进程是否存在并重新启动脚本
    记录:50多行程序中找出多写的一个字母e
    Android 平板中 自己定义键盘(popuwindow) 居于屏幕左下方 仿微信的password输入界面
  • 原文地址:https://www.cnblogs.com/xinfan1/p/11358158.html
Copyright © 2011-2022 走看看