首页 > 编程语言 >asyncio/trio fastdfs python client

asyncio/trio fastdfs python client

时间:2024-07-15 20:22:10浏览次数:14  
标签:trio python results client print import total def

Code

  • ts.py
#!/usr/bin/env python
"""
FastDFS并发测试脚本

Usage::
    $ python <me>.py 200 --show
"""

import functools
import itertools
import json
import os
import pickle
import sys
import time
from pathlib import Path
from typing import Callable, NoReturn, TypeVar

# pip install -U asynctor httpx rich fastdfs-client tqdm
import tqdm
from asynctor import bulk_gather, run, timeit
from asynctor.tasks import ThreadGroup
from httpx import AsyncClient
from rich import print

from fastdfs_client import FastdfsClient

T = TypeVar("T")


def catch_cost(func: Callable[..., T]) -> Callable[..., tuple[float, T]]:
    @functools.wraps(func)
    def wrapper(*args, **kw) -> tuple[float, T]:
        start = time.time()
        rv = func(*args, **kw)
        cost = round(time.time() - start, 1)
        return cost, rv

    return wrapper


def catch_async_cost(func):
    @functools.wraps(func)
    async def wrapper(*args, **kw):
        start = time.time()
        rv = await func(*args, **kw)
        cost = round(time.time() - start, 1)
        print(rv)
        return cost, rv

    return wrapper


@timeit
async def show_result(output: Path, dfs: FastdfsClient) -> None:
    """展示上传结果,验证返回的URL"""
    results = json.loads(output.read_bytes())
    print("Upload result:")
    print(results)
    urls = [url for _, url in results]
    if not (_nf := os.getenv("NO_FETCH")) or _nf == "0":
        # 使用协程并发请求图片URL,验证是否能按预期拿到图片
        async with AsyncClient(follow_redirects=True, timeout=80) as client:
            checks = (client.get(i) for i in urls)
            rs = await bulk_gather(checks, limit=50)  # 同一时刻的并行协程数为50
        print("URL concurrency result:\nidx\tstatus_code\telapsed\turl\tContentLength")
        for i, r in enumerate(rs, 1):
            print(
                i,
                r.status_code,
                r.elapsed,
                r.url,
                len(r.content) if r.status_code == 200 else r.text,
            )
    else:
        print(f"{len(results) = }")
    if "-d" in sys.argv or "--delete" in sys.argv:
        print("=" * 20)
        await delete_all(urls, dfs)


@timeit
async def delete_all(urls: list[str], dfs: FastdfsClient) -> None:
    # results = multi_threads_delete(urls, dfs)
    results = await bulk_gather([catch_async_cost(dfs.delete)(url) for url in urls])
    for res in results:
        print(res)
    print(f"total={len(results)}; success={sum(isinstance(i, tuple) for i in results)}")


def multi_threads_delete(urls, dfs):
    """使用多线程批量删除远程文件"""
    with ThreadGroup(max_workers=30) as tg:  # 控制并发线程数为50
        for url in urls:
            tg.soonify(catch_cost(dfs.delete_file))(url)
    return tg.results


def abort(msg: str) -> NoReturn:
    print(f"[red]ERROR:[/red] {msg}")
    sys.exit(1)


def multi_threads_upload(client, total, images):
    # 多线程并发上传文件
    with ThreadGroup() as tg:
        for index, p in tqdm.tqdm(zip(range(total), itertools.cycle(images))):
            tg.soonify(catch_cost(client.upload_as_url))(p.read_bytes())
    return tg.results


async def upload_many(client, total, images):
    return await bulk_gather(
        [
            catch_async_cost(client.upload)(p.read_bytes())
            for _, p in tqdm.tqdm(zip(range(total), itertools.cycle(images)))
        ]
    )


@timeit
async def main() -> None:
    total = 10
    client = FastdfsClient(["dfs.waketzheng.top"])
    if args := sys.argv[1:]:
        if (a1 := args[0]).isdigit():
            total = int(a1)
        elif (p := Path(a1)).is_file():
            await show_result(p, client)
            return
        else:
            abort("Invalid argument `{a1}`! Must be int or filepath.")
    d = Path.home() / "Pictures"
    assert d.exists(), f"文件夹({d})不存在"
    images = list(d.rglob("*.jp*g")) + list(d.rglob("*.JP*G"))
    assert images, f"{d}中没有jpeg图片"
    # results = multi_threads_upload(client, total, images)
    results = await upload_many(client, total, images)
    try:
        res = json.dumps(results)
    except TypeError:
        print(results)
        success = [i for i in results if isinstance(i, tuple)]
        print(f"total={len(results)}; success={len(success)}")
        p = Path("err.pickle")
        size = p.write_bytes(pickle.dumps(results))
        print(f"Failed to dump results: Write err info to {p} with {size=}")
        res = json.dumps(success)
    (p := Path("output.json")).write_text(res)
    print(f"{total = }\nSave results to '{p}'.")
    if "--show" in args:
        await show_result(p, client)


if __name__ == "__main__":
    run(main)

Usage

  • Upload
python ts.py
  • Delete uploaded files
python ts.py output.json -d

标签:trio,python,results,client,print,import,total,def
From: https://www.cnblogs.com/waketzheng/p/18303886

相关文章

  • Python 安装使用图片裁剪脚本
    Sure!Here’saquickguidetoinstallingPythononWindows11:###Step1:DownloadPython1.GototheofficialPythonwebsite:[python.org](https://www.python.org/downloads/)2.Clickthe"DownloadPython"button.Thiswilldownloadthelatestv......
  • python网络编程---TCP协议进行
        在这里简单实现一个TCP服务器,用于监听来自客户端的连接,接收客户端发送的消息,并向客户端发送响应消息。下面我将详细解释这个代码的工作原理和各个部分的作用。    首先建立一个客户端(client),一个服务端(server),在客户端进行连接到运行在本地机器(IP地址为127.......
  • python中的re模块--正则表达式
    正则表达式,又称规则表达式。(英语:RegularExpression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本  re模块作用通过使用正则表达式,可以:测试字符串内的模式。——例如,可以测试输入字符串,以查......
  • Python从0到100(三十九):数据提取之正则(文末免费送书)
    前言:零基础学Python:Python从0到100最新最全教程。想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Python爬虫、Web开发、计算机视觉、机器学习、神经网络以及人工智能相关知......
  • Python从0到100(四十):Web开发简介-从前端到后端(文末免费送书)
    前言:零基础学Python:Python从0到100最新最全教程。想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Python爬虫、Web开发、计算机视觉、机器学习、神经网络以及人工智能相关知......
  • Python学习—集合篇 详细讲解,简单易掌握
    一、集合的定义集合(set)是一种无序且不包含重复元素的数据结构,集合可以使用大括号 {} 来创建。创建集合的两种方式:第一种:使用{}括号s0={1,2,3,4,5}print(s0,type(s0))#结果:{1,2,3,4,5}<class'set'>第二种:用set()函数来创建集合s1=set([1,2,3,4,......
  • Python学习代码示例合集
    PythonDemo示例合集PyDemo:Python学习代码示例合集介绍欢迎来到PyDemo,这是一个专为Python学习者设计的代码示例合集。无论你是编程新手还是经验丰富的开发者,PyDemo都将为你提供有用的代码片段,帮助你快速掌握Python编程的各种技巧和应用场景。项目背景Python作......
  • Python学习 - 字典篇 新手小白也能懂
    目录一、字典的定义二、字典的声明1.用{}声明2.dict()三、字典的键与值四、字典的常见操作1.in成员运算符2.可迭代(三种遍历类型)第一种第二种第三种3.get4.添加或修改元素5.删除6.更新字典五、结语一、字典的定义在Python中,字典是一种无序的、可变的数......
  • Python基础入门(一)
    Python基础入门(一)一、python语言介绍​ python是一种解释型、面向对象、动态数据类型的高级程序设计语言。​ Python由GuidvanRossum于1989年底发明,​ 第一个公开发行版发行于1991年。​ Python源代码遵循GPL(GNUGeneralPublicLicense)协议二、python特点​ ......
  • Python基础入门(二)
    Python基础入门(二)一、学习目标:掌握各种分支结构的使用方法掌握各种循环结构的使用方式掌握分支结构与循环结构的嵌套使用方式二、分支结构介绍根据指定条件是否成立确定是否执行相应的代码块:单分支结构二分支结构多分支结构分支结构嵌套三、单分支结......