• day39


    今日内容:

    1.异步同步 和 阻塞非阻塞 概念 ******

    2.异步回调 ******

        为什么需要回调

          子进程帮助主进程完成任务 处理任务的结果应该是、交给准进程

        其他方式也可以将数据交还给主进程

           1.shutdown 主进程会等所有任务完成

           2.result函数 会阻塞直到完成任务

            都会阻塞 导致效率降低 所以使用回调

       注意:

              回调函数什么时候被执行? 子进程完成时

              谁在执行回调函数? 主进程

       线程的异步回调

               使用方式都相同 唯一不同的是执行回调函数 是子进程在执行

    3.线程列队 ****

         列队

         堆栈

         优先级列队

    4.协程

         协程的目的是在单线程下实现并发

         为什么出现协程?因为cpython由于GIL 导致同一时间只有一个线程再跑

             意味着 如果你的线程序计算密集 多线程效率也不会提升

             如果是io密集型 有没有必要再单线程下实现并发 

             没有 我还开启多线程来处理io 子线程遇到io cpu切走 但是请问 你能保证一定切换到主线程吗? 不能保证

          有 如果可以 我在遇到io的时候转而去做计算 这样一来可以保证cpu一直在处理你的程序 当然时间太长也会切换

          总结:单线程下实现并发 将io阻塞时间用于执行计算 可以提高效率 原理:一直使用cpu直到超时

    怎么实现单线程并发?

        并发 指的是 看起来像是同时运行 实际上是在任务之间来回切换 同时需要保存执行的状态

        任务一堆代码 可以用函数装起来

         1.如何让两个函数切换执行

            yield可以保存函数的执行状态

            通过生成器还有实现为并发

            并发不一定提升效率 反而会降低效率 当任务全是计算时

           2.如何知道发生了io?从而切换执行

                目前咱们实现不了

       第三方模块 greenlet 可以实现并发 但是不能检测io

       第三方模块gevent 封装greenlet 可以实现单线程并发 并且可以检测io操作 自动切换

    同步异步:

     线程的三种状态:

        1.就绪

        2.运行

        3.阻塞

     阻塞 遇到了io操作 代码卡住 无法执行下一行 CPU会切换的其他任务

     非阻塞 雨阻塞相反 代码正在执行(运行状态)或者处于就绪状态

     阻塞和非阻塞描述的是运行的状态

     同步:提交任务必须等待任务完成 才能执行下一行

     异步:提交任务不需要等待任务完成立即执行下一行

     指的是一种提交任务的方式

    def task():
        for i in range(1000000):
            i += 1000
        print("11111")
    
    print("start")
    task() # 同步提交方式
    print("end")
    
    from threading import  Thread
    
    print("start1")
    Thread(target=task).start()  # 异步提交
    print("end1")

    2.利用回调完成生产者消费:

    from  concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
    from threading import current_thread
    import  os
    pool = ThreadPoolExecutor()
    
    # 爬虫  1.从网络某个地址获取一个HTML文件
    
    import requests # 该模块用于网络(HTTP)请求
    
    # 生产数据
    def get_data_task(url):
        print(os.getpid(),"正在生产数据!")
        # print(current_thread(),"正在生产数据!")
    
        response = requests.get(url)
        text = response.content.decode("utf-8")
        print(text)
        return text
    
    
    #   处理数据
    def parser_data(f):
        print(os.getpid(),"处理数据")
        # print(current_thread(), "处理数据")
        print("正在解析: 长度%s" % len(f.result()))
    
    
    urls = [
        "http://www.baidu.com",
        "http://www.baidu.com",
        "http://www.baidu.com",
        "http://www.baidu.com"
    ]
    
    if __name__ == '__main__':
        for url in urls:
            f = pool.submit(get_data_task,url)
            f.add_done_callback(parser_data)  # 回调函数是主进程在执行
            # 因为子进程是负责获取数据的  然而数据怎么处理 子进程并不知道  应该把数据还给主进程
        print("over")

    3.线程队列:

    import queue
    
    # 普通队列 先进先出
    q = queue.Queue()
    q.put("a")
    q.put("b")
    
    
    print(q.get())
    print(q.get())
    
    # 堆栈队列  先进后出 后进先出  函数调用就是进栈  函数结束就出栈 递归造成栈溢出
    q2 = queue.LifoQueue()
    q2.put("a")
    q2.put("b")
    print(q2.get())
    
    
    # 优先级队列
    q3 = queue.PriorityQueue()  # 数值越小优先级越高  优先级相同时 比较大小 小的先取
    q3.put((-100,"c"))
    q3.put((1,"a"))
    q3.put((100,"b"))
    print(q3.get())

    4.协程实现:

    mport time
    def task():
        while True:
            print("task1")
            time.sleep(4)
            yield 1
    
    
    def task2():
        g = task()
        while True:
            try:
                print("task2")
                next(g)
            except Exception:
                print("任务完成")
                break
    task2()

    5.greenlet使用:

    import greenlet
    
    import time
    def task1():
        print("task1 1")
        time.sleep(2)
        g2.switch()
        print("task1 2")
        g2.switch()
    
    def task2():
        print("task2 1")
        g1.switch()
        print("task2 2")
    
    g1 = greenlet.greenlet(task1)
    g2 = greenlet.greenlet(task2)
    
    g1.switch()

    1.实例化greenlet得到一对象 传入要执行的任务

      至少需要两个任务

    2.先让某一个任务执行起来 使用对象调用switch

    3.在任务的执行过程中 手动调用switch来切换

    6.gevent使用:

    from gevent import monkey
    monkey.patch_all()
    
    import gevent
    import time
    def eat():
        print('eat food 1')
        time.sleep(2)
        # gevent.sleep(1)
        print('eat food 2')
    
    def play():
        print('play 1')
        time.sleep(1)
        # gevent.sleep(1)
        print('play 2')
    
    g1=gevent.spawn(eat)
    g2=gevent.spawn(play)
    # g1.join()
    # g2.join()
    
    gevent.joinall([g1,g2])
    print('')

    1.spawn函数传入你的任务

    2.调用join 去开启任务

    3.检测io操作需要打开monkey补丁 就是一个函数 在程序最开始的地方调用它

         

  • 相关阅读:
    Python函数式编程学习笔记
    DOS常用命令总结
    Python高级特性学习笔记
    Git bash使用中...
    《零基础入门学习Python》学习过程笔记【30模块中的函数,os模块,ospath模块中的函数(看了一点)】
    这两天将这段时间的python笔记常用知识复习了一遍...前天半夜吃了盘烤羊肉..得了急性肠炎
    《零基础入门学习Python》学习过程笔记【29对文件进行分割】(没看)
    《零基础入门学习Python》学习过程笔记【28文件】
    《零基础入门学习Python》学习过程笔记【27集合】
    用python写一个简单的用户登陆程序(要求写成函数)
  • 原文地址:https://www.cnblogs.com/hui2002/p/9954811.html
Copyright © 2020-2023  润新知