社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

200行代码简单实现协程下载器,带你了解Python全部协程新特性

一个普普通通简简单单平平凡凡的神 • 8 年前 • 432 次点击  

Python官方这两年为了支持协程,下了不少工夫,增加了await/async关键字不说,还增加了大量魔法方法来完善对协程的支持,理论知识的学习少不了实践的支持,昨天闲来无事实现了一个简单的基于协程的下载器。将协程相关的魔法方法一并纳入。现分享出来供大家检阅。

ShichaoMa/async-downloader​github.com图标
  • 程序支持多个worker同时下载文件。
  • 支持command line, redis, file多种下载信息来源,同时还支持自定义。
  • 支持自定义实现async download方法。
  • 使用简单,一键执行。

安装

pip install async-downloader

用法

usage: a-download [-h] {file,redis,cmdline} ...

Async downloader

positional arguments:
  {file,redis,cmdline}  Source.
    file                file source
    redis               redis source
    cmdline             command line source

optional arguments:
  -h, --help            show this help message and exit.
Command 'file'
usage: a-download file [-h] --workers WORKERS [--download DOWNLOAD]
                       [--proxy PROXY] [--proxy-auth PROXY_AUTH] --path PATH

Command 'redis'
usage: a-download redis [-h] --workers WORKERS [--download DOWNLOAD]
                        [--proxy PROXY] [--proxy-auth PROXY_AUTH]
                        [-rh REDIS_HOST] [-rp REDIS_PORT] [-rk REDIS_KEY]
                        [--idle]

Command 'cmdline'
usage: a-download cmdline [-h] --workers WORKERS [--download DOWNLOAD]
                          [--proxy PROXY] [--proxy-auth PROXY_AUTH] --filename
                          FILENAME --url URL

不同的下载数据源使用不同的参数。对于自定义的数据源类,可以保存在当前目录sources.py中,程序会对其进行动态加载。数据源类编写方法如下:

class Source(object):
    """
    source 基类
    """

    def __aiter__(self):
        """
        返回一个可以使用async for进行迭代的异步可迭代对象。
        :return:
        """
        return self

    async def __aenter__(self):
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """
        进行资源关闭时使用
        :param exc_type: 
        :param exc_val: 
        :param exc_tb: 
        :return: 
        """
        pass

    async def __anext__(self):
        """
        返回'{"url": "", "filename": ""}'
        :return: 
        """
        return NotImplemented

    @staticmethod
    def enrich_parser(sub_parser):
        """
        需要专属命令行参数时需要实现
        :param sub_parser: 
        :return: 
        """
        pass

继承Source类,实现特定方法即可。一般来说,对于需要资源关闭的数据源,可以通过重写__aexit_来实现资源的关闭,每个数据源都必须实现__anext__,返回一个url和file组成的json字符串。

例子参见:

https://github.com/ShichaoMa/async-downloader/blob/master/async_downloader/sources.py​github.com

对于FileSource和CmdlineSource,执行完文件中或命令行中的下载源信息程序即可退出,但RedisSource可能是一个持续的过程,通过RedisSource专用参数--idle来保证长驻执行。

--workers用来规定同时参与下载的协程任务最大数量。

--download可以指定一个自定义的下载方法: module.function

async def download(self, url, filename, chunk_size=1024000):
    import asyncio
    print("download")
    await asyncio.sleep(10)

自定义下载方法必须是异步的。

机制

程序使用一个异步生成器来分发下载任务

异步生成器是Python最新的特性,在异步函数使用yield就会返回一个异步生成器。

调用生成器的.asend方法,获取任务,通过一个tasks队列来保证同时进行的下载任务数不超过限定数量。

通过生成器发送False来关闭生成器,从而退出主协程。

结语

程序大量使用了python新特性,有兴趣的同学可以直接去看源码,除去注释不到200行。简单易懂。

ShichaoMa/async-downloader​github.com图标

欢迎Star或Fork。


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/osa5EeNAkZ
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/11016