协程和断点上传
线程中的队列
我们经常会遇到这样的一个问题,这里有成千上万条数据,每次需要取出其中的一条数据进行处理,那么引入多线程该怎么进行任务分配?
我们可以将数据进行分割然后交给多个线程去跑,可是这并不是一个明智的做法。在这里我们可以使用队列与线程相结合的方式进行任务分配。
队列线程的思想: 首先创建一个全局共享的队列,队列中只存在有限个元素,并将所有的数据逐条加入到队列中,并调用队列的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就是文件已经被删除了
来源:https://www.cnblogs.com/WBaiC1/p/10986728.html