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就是文件已经被删除了 
优质内容筛选与推荐>>
1、Ext.grid
2、新建一个controller并指定为默认的方法
3、Nuxt.js使用mint-ui
4、性能测试报告模板
5、NOIP2015 运输计划 (树上差分+二分答案)


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn