程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

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

发布于2019-08-29 14:44     阅读(759)     评论(0)     点赞(12)     收藏(5)


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。



所属网站分类: 技术文章 > 博客

作者:喜洋洋与红太狼

链接:https://www.pythonheidong.com/blog/article/68593/8b03382d59fc9f60e693/

来源:python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

12 0
收藏该文
已收藏

评论内容:(最多支持255个字符)