Python使用多线程并发测试FastDFS文件上传、删除

代码如下:

# main.py
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 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


@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)
        delete_all(urls, dfs)


@timeit
def delete_all(urls: list[str], dfs: FastdfsClient) -> None:
    """使用多线程批量删除远程文件"""
    with ThreadGroup() as tg:
        for url in urls:
            tg.soonify(catch_cost(dfs.delete_file))(url)
    results = tg.results
    for res in results:
        print(res)
    print(f"total={len(results)}; success={sum(isinstance(i, tuple) for i in results)}")


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


@timeit
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():
            run(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图片"
    # 多线程并发上传文件
    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())
    try:
        res = json.dumps(tg.results)
    except TypeError:
        print(tg.results)
        success = [i for i in tg.results if isinstance(i, tuple)]
        print(f"total={len(tg.results)}; success={len(success)}")
        p = Path("err.pickle")
        size = p.write_bytes(pickle.dumps(tg.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:
        run(show_result(p, client))


if __name__ == "__main__":
    main()

使用:

python main.py 120 --show

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/776345.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt 基础组件速学 鼠标和键盘事件

学习目标: 鼠标事件和键盘事件应用 前置环境 运行环境:qt creator 4.12 学习内容和效果演示: 1.鼠标事件 根据鼠标的坐标位置,做出对应的事件。 2.键盘事件 根据键盘的输入做出对应操作 详细主要代码 1.鼠标事件 #include "main…

C++新特性

C新特性主要体现在语法改进和标准库扩充两个方面。以下是一些主要的C新特性: 语法改进 统一的初始化方法:C11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型。这种定义…

vue.js微商城后台管理系统

一.需要运行的效果 20240701-231456 二.代码(解析) 首先,为项目添加依赖: yarn add element-plus --save yarn vue-router4 --save 新建一个项目包,然后命名为商品管理,在components中新建几个vue文件。 …

全新UI自助图文打印系统小程序源码 PHP后端 附教程

最新自助图文打印系统和证件照云打印小程序源码PHP后端,为用户用户自助打印的服务,包括但不限于文档、图片、表格等多种格式的文件。此外,它们还提供了诸如美颜、换装、文档打印等功能,以及后台管理系统,方便管理员对打…

TreeMap、HashMap 和 LinkedHashMap 的区别

TreeMap、HashMap 和 LinkedHashMap 的区别 1、HashMap2、LinkedHashMap3、TreeMap4、总结 💖The Begin💖点点关注,收藏不迷路💖 在 Java 中,TreeMap、HashMap 和 LinkedHashMap 是三种常用的集合类,它们在…

Ubuntu配置GitHub(第一次clone/push)

文章目录 1. 安装Git&检查连接2. 注册GitHub3. 生成&GitHub添加SSH3.1. 检查&删除已有id_rsa3.2. 生成SSH3.3. GitHub添加id_rsa.pub SSH3.4. 检查SSH 4. 继续开发可以参考参考 1. 安装Git&检查连接 安装 sudo apt-get install git检查SSH连接 ssh -T gitgi…

Qt 基础组件速学 事件过滤器

学习目标:理解事件过滤器 前置环境 运行环境:qt creator 4.12 学习内容和效果演示: Qt 提供了事件过滤器的机制,允许我们在事件到达目标对象之前对事件进行拦截和处理。这在以下情况下非常有用: 全局事件处理: 我们可以在应用程序级别安装一个事件过…

数据结构——(双)链表

文章目录 1. 定义 2. 双链表和单链表的区别 3. 代码示例 3.1 双链表节点和结构定义 3.2 初始化双链表 3.3 返回双链表的长度 3.4 在指定位置插入元素 3.5 在末尾插入元素 3.6 删除指定位置的元素并返回被删除的元素 3.7 删除末尾元素 3.8 获取指定位置的元素 3.9 修…

【IT领域新生必看】探索Java中的对象创建:深入理解`new`与`clone`的对比

文章目录 引言什么是new关键字?使用new关键字的基本语法示例: 什么是clone方法?使用clone方法的基本语法示例: new与clone的区别内存分配与初始化调用方式适用场景性能 new关键字的优缺点优点缺点 clone方法的优缺点优点缺点 深入…

机器学习---线性回归

1、线性回归 例如:对于一个房子的价格,其影响因素有很多,例如房子的面积、房子的卧室数量、房子的卫生间数量等等都会影响房子的价格。这些影响因子不妨用 x i x_{i} xi​表示,那么房价 y y y可以用如下公式表示: y …

【贪心 堆 优先队列】502. IPO

本文涉及知识点 贪心 堆 优先队列 LeetCode502. IPO 假设 力扣(LeetCode)即将开始 IPO 。为了以更高的价格将股票卖给风险投资公司,力扣 希望在 IPO 之前开展一些项目以增加其资本。 由于资源有限,它只能在 IPO 之前完成最多 k…

评价ChatGPT与强人工智能的未来

在人工智能领域,ChatGPT的出现无疑是一个里程碑事件。它不仅展示了自然语言处理技术的巨大进步,也引发了人们对于强人工智能(AGI)的无限遐想。本文将从多个角度评价ChatGPT,并探讨强人工智能距离我们还有多远。 ChatGP…

【Leetcode笔记】406.根据身高重建队列

文章目录 1. 题目要求2.解题思路 注意3.ACM模式代码 1. 题目要求 2.解题思路 首先,按照每个人的身高属性(即people[i][0])来排队,顺序是从大到小降序排列,如果遇到同身高的,按照另一个属性(即p…

鸿蒙开发:Universal Keystore Kit(密钥管理服务)【密钥导入介绍及算法规格】

密钥导入介绍及算法规格 如果业务在HUKS外部生成密钥(比如应用间协商生成、服务器端生成),业务可以将密钥导入到HUKS中由HUKS进行管理。密钥一旦导入到HUKS中,在密钥的生命周期内,其明文仅在安全环境中进行访问操作&a…

类继承-多继承虚继承

#include<iostream> using namespace std; class A1 { public:int a 10;}; class A2 { public:int b 20; }; class B :public A1, public A2 { public:int c 30; }; int main(){B b;cout << b.a << b.b << b.c << endl;return 0; } 如果基类…

十五、小型电脑没有数字键及insert,怎么解决IDEA快速插入getset构造这些方法

&#x1f33b;&#x1f33b;目录 一、小型电脑没有数字键及insert&#xff0c;怎么解决IDEA快速插入getset构造这些方法 一、小型电脑没有数字键及insert&#xff0c;怎么解决IDEA快速插入getset构造这些方法 解决&#xff1a; 1.winR打开搜索 2.osk回车 屏幕就出现了这样的一…

windows USB 设备驱动开发- 不同模型下的控制传输

在不同的模型下&#xff0c;USB控制传输会有不同的特点&#xff0c;但是任何控制传输的目标都始终是默认端点。 接收者是设备的实体&#xff0c;其信息&#xff08;描述符、状态等&#xff09;是主机感兴趣的。请求可进一步分为&#xff1a;配置请求、功能请求和状态请求。 发…

二刷力扣——单调栈

739. 每日温度 单调栈应该从栈底到栈顶 是递减的。 找下一个更大的 &#xff0c;用递减单调栈&#xff0c;就可以确定在栈里面的每个比当前元素i小的元素&#xff0c;下一个更大的就是这个i&#xff0c;然后弹出并记录&#xff1b;然后当前元素i入栈&#xff0c;仍然满足递减…

基于.NET开源游戏框架MonoGame实现的开源项目合集

前言 今天分享一些基于.NET开源游戏框架MonoGame实现的开源项目合集。 MonoGame项目介绍 MonoGame是一个简单而强大的.NET框架&#xff0c;使用C#编程语言可以创建桌面PC、视频游戏机和移动设备游戏。它已成功用于创建《怒之铁拳4》、《食肉者》、《超凡蜘蛛侠》、《星露谷物…

linux之管道重定向

管道与重定向 一、重定向 将原输出结果存储到其他位置的过程 标准输入、标准正确输出、标准错误输出 ​ 进程在运行的过程中根据需要会打开多个文件&#xff0c;每打开一个文件会有一个数字标识。这个标识叫文件描述符。 进程使用文件描述符来管理打开的文件&#xff08;FD--…