zoukankan      html  css  js  c++  java
  • day38,线程队列,协程

                                                                                  协程和断点上传

    线程中的队列

    我们经常会遇到这样的一个问题,这里有成千上万条数据,每次需要取出其中的一条数据进行处理,那么引入多线程该怎么进行任务分配?

    我们可以将数据进行分割然后交给多个线程去跑,可是这并不是一个明智的做法。在这里我们可以使用队列与线程相结合的方式进行任务分配。

    队列线程的思想: 首先创建一个全局共享的队列,队列中只存在有限个元素,并将所有的数据逐条加入到队列中,并调用队列的join函数进行等待。之后便可以开启若干线程,线程的任务就是不断的从队列中取数据进行处理就可以了。

    from queue import Queue,LifoQueue,PriorityQueue
    
    # 与进程中的Joinablequeue  使用方式一模一样  但是 不具备IPC
    # q = Queue()
    
    # q.put("123")
    # q.put("456")
    
    # print(q.get())
    # print(q.get())
    
    # # print(q.get(block=True,timeout=3))
    # q.task_done()
    # q.task_done()
    # q.join()
    # print("over")
    
    # last in first out 后进先出   先进 后出   模拟堆栈 ===========================================================
    # LifoQueue
    
    # 除顺序以外别的都一样
    # lq = LifoQueue()
    #
    # lq.put("123")
    # lq.put("456")
    #
    # print(lq.get())
    # print(lq.get())
    
    # 具备优先级的队列
    # PriorityQueue ================================================================
    # 可以存储一个可以比较大小的对象    比较越小的优先级越高    自定义对象 不能使用比较运算符  所以不能存储
    
    class A(object):
        def __init__(self,age):
            self.age = age
    
        # def __lt__(self, other):
        #     return self.age < other.age
        #
        # def __gt__(self, other):
        #     return self.age > other.age
    
        def __eq__(self, other):
            return self.age == other.age
    
    a1 = A(50)
    a2 = A(50)
    
    print(a1 == a2)
    # print(a1 is a1)
    
    # pq = PriorityQueue()
    # pq.put("a")
    # pq.put("A")
    # pq.put("C")
    #
    #
    # print(pq.get())

    协程:

    什么是协程:

      是单线程下的并发,又称微线程,纤程。一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。

    需要强调的是:

          1. python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫交出cpu执行权限,切换其他线程运行)
          2. 单线程内开启协程,一旦遇到io,就会从应用程序级别(而非操作系统)控制切换,以此来提升效率(!!!非io操作的切换与效率无关)

    对比操作系统控制线程的切换,用户在单线程内控制协程的切换

    优点如下:

          1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
          2. 单线程内就可以实现并发的效果,最大限度地利用cpu

    缺点如下:

          1. 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程来尽可能提高效率
          2. 协程本质是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程

    gevent 中的monkey 补丁是协程中重要的接口,因为在我们使用gevent来实现单线程并发的时候是不能够实现进行io操作,所以就有了monkey这个接口

    帮助gevent来实现对io的操作,这里还需要注意的是在补丁的时候是,需要在py文件的商法实现补丁,在文件的下方法无法实现补丁的效果

    如何实现单线程并发(协程):

    # gevent 不具备检测IO的能力  需要为它打补丁  打上补丁之后就能检测IO
    # 注意补丁一定打在最上面    必须保证导入模块前就打好补丁
    from gevent import monkey
    monkey.patch_all()   #
    
    from threading import current_thread
    import gevent,time
    
    
    def task1():
        print(current_thread(),1)
        print("task1 run")
        # gevent.sleep(3)
        time.sleep(3)
        print("task1 over")
    
    def task2():
        print(current_thread(),2)
        print("task2 run")
        print("task2 over")
    
    # spawn 用于创建一个协程任务
    g1 = gevent.spawn(task1)
    g2 = gevent.spawn(task2)
    
    # 任务要执行,必须保证主线程没挂  因为所有协程任务都是主线在执行   ,必须调用join来等待协程任务
    # g1.join()
    # g2.join()
    # 理论上等待执行时间最长的任务就行 , 但是不清楚谁的时间长 可以全部join
    
    gevent.joinall([g1,g2])
    print("over")

    断点下载文件:

     在讲断点下载文件,需要注意的是几种状态,其他的都是之前学的知识

    info = {"filename":True} 或者 info = {"filename":false} 或者 info = {}
    
    在info中为True 就是已完成 为false就是未完成
    
    目前有四种状态
    文件存在: 
             ----> 下载完成   文件已存在,且info 中的value 为True 并且文件这个路径也是存在的就是下载完成状态 
                  
             ----> 下载了文件,但是文件没有被下载完成
                   文件下载文件未完成,状态是在info中的的value 为false 并且文件的路径也是存在的 
    
    文件不存在:  
             ----> 新的任务
                   
                   文件不存在,这个在value中的filename不存在,就是一个空{}这就记录为是新的任务
    
             ----> 文件被删除了 
                  
                   文件路劲不存在,在info 中的状态是false就是文件已经被删除了 
  • 相关阅读:
    图片切换的练习
    固定定位
    绝对定位
    相对定位
    全局作用域 变量声明
    3种循环语句 JS基础
    解除绑定事件 和 封装兼容性addEvent 来处理针对于不同浏览器的兼容方法
    插入排序法 猴子选大王 检索的数组 验证身份证号码 练习
    [z]JSONP例子
    ireport related
  • 原文地址:https://www.cnblogs.com/WBaiC1/p/10986728.html
Copyright © 2011-2022 走看看