021-uv使用指南

uv使用指南

1: Introduction

  • uv 是一款用 Rust 开发的高性能 Python 包管理器,旨在统一和简化 Python 的包管理、项目管理和环境管理流程,
  • 核心功能对比
功能领域传统工具uv对应命令备注
包管理pip, pip-toolsuv pip install
虚拟环境virtualenvuv venv
依赖锁定pip-compile + requirements.txt自动生成 uv.lock
Python版本管理pyenvuv python install

2:uv的优势

  • 极致的速度:得益于 Rust 的实现、并行网络请求和智能缓存,uv 在依赖解析和包安装速度上相比传统工具(如 pip 和 Poetry)有显著提升。
  • 功能全面集成:它将 Python 项目开发中常用的多种工具功能集成于一身,你不再需要频繁在 pip、virtualenv、pipx 等工具间切换。
  • 符合 Python 标准:uv 的项目管理基于 pyproject.toml 文件,遵循 PEP 621 标准,并支持生成跨平台的锁文件 uv.lock,保证了项目在不同环境下依赖的一致性。
  • uv 提供了更强大的依赖管理功能,可以自动解析和安装依赖,避免手动安装和管理依赖的麻烦。

3:安装与配置uv

3.1 安装uv

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 在某些计算集群或受限环境中,默认安装路径可能不合适。你可以通过设置环境变量 UV_INSTALL_DIR 来自定义安装目录,并通过 INSTALLER_NO_MODIFY_PATH=1 阻止其自动修改 shell 配置文件

# macOS 和 Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
choco install uv

# pip 
pip install uv

# 验证
uv --version

3.2 配置uv镜像源

1
2
3
4
5
# 项目级配置(推荐): 在项目的 pyproject.toml 文件中添加

[[tool.uv.index]]
url = 'https://mirrors.aliyun.com/pypi/simple'
default=true

4: uv核心功能与常用命令

4.1 项目管理与依赖管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# uv 可以帮你初始化项目、添加依赖并自动生成锁文件
# 1:初始化新项目
mkdir my_project && cd my_project
uv init #这会在当前目录生成一个基本的 pyproject.toml 文件
# 2:添加依赖
uv add requests          # 添加生产依赖
uv add pytest --dev      # 添加开发依赖
uv add -r requirements.txt # 从现有requirements.txt文件导入
# 这些命令会自动更新 pyproject.toml 并安装相应的包

# 3:同步依赖与运行项目
uv sync                  # 安装所有依赖并创建/更新锁文件
uv run python main.py    # 在项目专属环境中运行命令,无需手动激活虚拟环境
uv run python main.py --lock

4.2 虚拟环境管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 1: 创建虚拟环境
uv venv                 # 在当前目录创建 .venv 虚拟环境
uv venv --python 3.12 my_env  # 创建指定Python版本和名称的环境

# 2: 列出所有虚拟环境
uv venv list

# 3: 激活虚拟环境
source .venv/bin/activate
.venv\Scripts\activate # Windows
uv venv activate my_env

# 4: 删除虚拟环境
uv venv delete my_env

4.3 工具管理(uv tool)

  • 类似于 pipx,uv tool 用于在隔离环境中安装和运行 Python 命令行工具
1
2
3
uv tool install ruff              # 安装代码检查工具 ruff
uv tool run ruff check .          # 直接运行工具
uv tool run ruff check .          # 也可使用别名 uvx

4.4 Python版本管理

4.4.1 安装和使用特定 Python 版本

  • uv 可以直接安装和管理多个版本的 Python 解释器,替代 pyenv。
1
2
3
uv python install 3.12    # 安装 Python 3.12
uv python list            # 列出已安装的 Python 版本
uv venv --python 3.12     # 使用指定版本创建虚拟环境

4.4.2 uv进阶使用技巧

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 依赖数分析
uv tree

# 依赖锁定与同步
uv lock --upgrade-package numpy  # 仅升级指定包
uv sync --force                  # 强制同步环境,即使本地有修改

# 单文件脚本依赖管理: uv 支持基于 PEP 723 标准的单文件 Python 脚本,可以在脚本内部通过注释块声明依赖

uv init --script myscript.py  # 初始化一个脚本文件
uv add --script myscript.py rich #为脚本添加依赖,uv 会自动在脚本顶部生成依赖元数据
uv run myscript.py 运行脚本,uv #会自动处理这些依赖

01-005-lppKDB脚本

1:KDB 简介

2:KDB 安装

3:KDB+/Q 脚本

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
 wans//utf-8 ------------kdb+ Common Statments ---kdb+常用语句----------

// kdb+ tutorials https://www.timestored.com/kdb-guides/?utm_source=qstudio&utm_medium=app&utm_campaign=qstudio
// kdb+ keywords  https://www.timestored.com/kdb-guides/kdb-keyword-reference

// list
y:(`cpp;`python;`go;`java) // list of four symbols, y is variable name
y

y:(`cpp`python`go`java) // list of four symbols, Note not semicolon
y

y2:("symbol may have interior blanks") // string
y2
type y2

// string convert symbol  将字符串转换为符号
s: "hello world"
symbolList: `$(" " vs s) // use vs 函数 ; $ 是类型转换操作符
symbolList
symbolList[1]

// table  https://www.wenjiangs.com/doc/p4btamfe
// 创建表
userTable:([]name:(`cpp`go`python);[]amount:(100,200,300);[]price:(10.5,95.5,60.5))
// 获取表信息
cols userTable
userTable.name
meta userTable // 展示table meta信息: 列名, 列类型,其他信息

val:flip`name`id!(`John`Jenny`Jonathan;9 18 27) // flip list转为列,也就是list转为table

val:flip`name`id!(`John`Jenny`Jonathan;9 18 27)
idTable:flip (enlist`eid)!enlist 99 198 297
newTable: idTable ! val //
// select
select from responsev4 where sym like "*zjzg_test_1*", qid like "*6dc47d9e-b6bd-47e5-aa59-8ac4dc701776*",entrustno=100016,status=1

select count qid from responsev4  where sym like "*zjzg_test_1*"

select from responsev4 where sym like "*zjzg_test_1*",securityID like "*600570*"

select from responsev4 where qid like "*b9edeee9-88e3-4b45-8231-da6d1136a34d*", entrustno = 10009,status = 2

select from responsev4 where sym like "*zjzg_test_1*", entrustno = 10003

select count qid from responsev4 where sym like "*zjzg_test_1*"

0!select sym,qid,entrustno from responsev4Qid where sym like "*zjzg_test_1*", entrustno = 10001

`open xdesc select from tableB // by open filed sort

`resptime xdesc (select  from responsev4Qid where sym like "*2668i*") // sort xasc, xdesc

// 查询聚合语句
select count(qid) from responsev4 where sym like "*9878*"   , status in(2,3);
select sum(cumqty) from responsev4 where sym like "*9878*"   , status in(2,3);

// delete
delete columns from table  / delete columns
delete from table where clause
delete from `responsev4Qid where qid like "delete_test_1"
delete from `assetTab  where i>=0  // 清空表
drop `Stu    // 删除表

// insert
`trade insert (`hsbc`apple;302.0 730.40;3020 3012;09:30:17.00409:15:00.000)
insert[`cancelTab;enlist `sym`qid`entrustno


// update 更新语句
update entrustno: 10005 from (0!select from responsev4Qid where qid like "*c3c63d45-4c9c-4de6-8276-86b9a516c924*")
upd0['responsev4;update status:5i, cumqty:0i, avgpx:0.0f, note: `DFD from ( 0!select from responsev4Qid where sym like "*guangda test*")]


// insert 插入语句
insert[`cancelTab;enlist `sym`qid`entrustno!(`zjzg_test_1,`t7912h9sh3, 10004)];

// 发布数据.u.pub
u.pub[`cancelTab;enlist`sym`qid`entrustno!(`zjzg_test_1 ,`t7912h9sh3, 10003)];


// kdb 撤单指令
cancelReq:{[q] t:select sym, qid, entrustno from (select from responsev4Qid where qid = q); upd0[`cancelTab;t];}
cancelReq[`$"a3dcb0ea-d26a-40d6-87b6-98a6b705fc4e"]

//  time
select from responsev4Qid where resptime.time>09:40:00 ,status=6, note like "*ACK*"

// group

// cancel order

cancelReq:{[q] t:select sym, qid, entrustno from (select from responsev4Qid where  qid like "*dca382c8*"  ); upd0[`cancelTab;t];}

cancelReq[`$"527ed110-6e4a-11ef-8997-00163e313bec"]


// limit stat
select count qid by `second$time from request where sym like "*1099*"
select count qid by `second$resptime  from responsev4Qid

// not sym like "*gs2828i*"

//
(1) 查看状态不正常的订单,比如status=0,3
(2) qmt查看账户交易是否正常,GT停用启用该账户:
(3) 重启下游交易程序,并查看订单状态是否正常回报;
(4) 没回报的话,手动修改订单状态
(5) 没有报出去order,状态为3,置为5
(6) qmt成交,cim丢失了,先把该账户对应订单置为0,重启客户端,停用启用,在重启下游交易程序


//  统计
r: select sym,qid,time from request where sym=`mshw_ubs26_03
v: select  sym,qid,resptime,status from responsev4 where status=1, sym in (`mshw_ubs26_03), not null resptime
v_unkeyed: select  sym,qid,resptime,status from responsev4 where status=1, sym in (`mshw_ubs26_03)
v_keyed: `qid xkey v_unkeyed // 将右表 v_unkeyed 转换为以 qid 为键的键控表
jt: r ij v_keyed // lj, ij
select from jt  where not null resptime
select sym,qid,time,latency: resptime - time  from jt  where not null resptime
select sym,qid,time,latency_ms: 0.001 * (resptime - time)    from jt  where not null resptime

select sym,qid,time,latency: 1000000*(resptime - time) from jt  where not null resptime ,qid=`$"3fcac912-b078-11f0-b812-00163e313bec" //含有-, `$"string" 先转字符串再转 symbol

01-Docker部署go项目

Docker部署go项目

1: 准备 Go 项目

  • 确保 Go 项目已经编写完成,并且可以在本地正常运行。

  • 项目目录结构如下:

    1
    2
    3
    4
    5
    
    ├── main.go
    ├── go.mod
    ├── go.sum
    ├── Dockerfile
    ├── Makefile
    
    • main.go:Go 项目的入口文件。
    • go.mod:Go 项目的依赖管理文件。
    • go.sum:Go 项目的依赖管理文件。
    • Dockerfile:Dockerfile 文件,用于构建 Docker 镜像。
    • Makefile:Makefile 文件,用于简化构建过程。

2: 编写 Dockerfile

2.1 基础镜像

  • 在项目根目录下创建 Dockerfile 文件,内容如下:

010-update-alternatives安装gcc多版本

update-alternatives安装gcc多版本

1: 安装update-alternatives

  • 该工具属于dpkg软件包管理系统的核心组件,一般系统已预装。若提示命令不存在,可通过以下命令安装
  • 安装: sudo apt install dpkg
  • 验证: update-alternatives --help

2: ​添加旧版本软件源(针对gcc-4.8.5)

  • 由于Ubuntu 2024.04的默认源可能不包含gcc-4.8.5,需要手动添加旧版仓库:
1
2
sudo sed -i '$a deb http://archive.ubuntu.com/ubuntu/ xenial main universe' /etc/apt/sources.list
sudo apt update

3: 安装各版本GCC/G++

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 安装gcc/g++ 4.8.5(需依赖旧版源)
sudo apt install gcc-4.8 g++-4.8

# 安装gcc/g++ 7和9
sudo apt install gcc-7 g++-7 

#(默认源支持)
sudo apt install gcc-9 g++-9


# 如果apt 安装不了,手动下载安装
https://ftp.gnu.org/gnu/gcc/

4: 配置update-alternatives

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 添加gcc版本(优先级数值越大优先级越高)
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 40 \ 
--slave /usr/bin/g++ g++ /usr/bin/g++-4.8 \
--slave /usr/bin/gcov gcov /usr/bin/gcov-4.8

sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 70 \ 
--slave /usr/bin/g++ g++ /usr/bin/g++-7 \
--slave /usr/bin/gcov gcov /usr/bin/gcov-7

sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 90 \ 
--slave /usr/bin/g++ g++ /usr/bin/g++-9 \
--slave /usr/bin/gcov gcov /usr/bin/gcov-9

sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 130 \ 
--slave /usr/bin/g++ g++ /usr/bin/g++-13 \
--slave /usr/bin/gcov gcov /usr/bin/gcov-13

5: 切换默认版本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 交互式选择版本
sudo update-alternatives --config gcc

# 输出示例:
There are 3 choices for the alternative gcc (providing /usr/bin/gcc).

  Selection    Path              Priority   Status
------------------------------------------------------------
* 0            /usr/bin/gcc-9     90        auto mode
  1            /usr/bin/gcc-4.8   40        manual mode
  2            /usr/bin/gcc-7     70        manual mode
  3            /usr/bin/gcc-9     90        manual mode

Press <Enter> to keep the current choice[*], or type selection number: 

6: 版本验证

1
2
gcc --version  # 应显示当前选择的版本
g++ --version  # 应与gcc版本一致

020-pyenv管理python多版本

pyenv 管理 python 多版本

1:virtualenv

  • virtualenv 所要解决的是同一个库不同版本共存的兼容问题。例如项目 A 需要用到 requests 的 1.0 版本,项目 B 需要用到 requests 的 2.0 版本。如果不使用工具的话,一台机器只能安装其中一个版本,无法满足两个项目的需求。

019-文档转为markdown

将非 Markdown 格式的文档转换为 Markdown

1:介绍

  • 这是一个由微软开源的 Python 工具,可以将非 Markdown 格式的文档转换为 Markdown 格式,支持 PDF、PPT、Word 和 Excel 等多种文件类型,为文档的索引和文本分析提供了极大的便利。

017-pysftp SFTP Pool

pysftp SFTP Pool

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

import pysftp
import os
import sys
import time
import paramiko
from queue import Queue, Empty

# -----------------------------


from etc import config
import utils
from utils import logger_web
from utils import logger_lms as logger


# -----------------------------
broker=config.LMS["broker"]
notifier_list=config.Notifier
notifier_list2=config.Notifier2

# -----------------------------

class SFTPConnectionPool:
    """SFTP连接池"""
    def __init__(self,host,port,username,password,max_connections=20):
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.max_connections = max_connections
        self.pool=Queue(maxsize=max_connections)
        self.cnopts = paramiko.SSHClient()
        self.cnopts.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        # self.cnopts.hostkeys = None
        self._init_pool()

    def _init_pool(self):
        for _ in range(self.max_connections):
            conn=self._create_conn()
            if conn:
                self.pool.put(conn)
            else:
                logger.error("初始化SFTP连接池失败")

    def _create_conn(self):
        transport=paramiko.Transport((self.host,self.port))
        transport.connect(username=self.username,password=self.password)
        return paramiko.SFTPClient.from_transport(transport)

    def get_conn(self):
        try:
            return self.pool.get(timeout=10)
        except Empty:
            logger.error("SFTPConnPool no avaiable connections ...")

    def release_conn(self,conn):
        if conn:
            self.pool.put(conn) # 将对象放回连接池
        else:
            logger.warning("SFTPConnPool attempted to release a None connection")

    def close_all_conn(self):
        while not self.pool.empty():
            conn=self.pool.get()
            if conn:
                conn.close()
            else:
                logger.warning("SFTPConnPool Found a None connection in the pool")




class SFTPClient:
    def __init__(self, host,port, username, password, upload_dir, download_dir):
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.upload_dir = upload_dir
        self.download_dir = download_dir
        self.max_retries = 3
        self.retry_delay = 5
        self.pool=SFTPConnectionPool(host,port,username,password)

    def ensure_connected(self):
        """确保SFTP连接是活跃的,如果断开则重连"""
        sftp=self.pool.get_conn()
        if not sftp:
            return False
        try:
            sftp.listdir()
            return True
        except Exception as e:
            logger.error("SFTPClient connection check failed, error={}".format(e))
            self.pool.release_conn(sftp)
            time.sleep(3)
            return False

    def upload_file(self, local_file):
        logger.info(f"SFTPClient start upload file={local_file} to remote_path={self.upload_dir}")
        if not os.path.exists(local_file):
            logger.error("SFTPClient UploadFile ={} does not exist".format(local_file))
            return False
        for attempt in range(self.max_retries):
            try:
                if not self.ensure_connected():
                    continue
                sftp=self.pool.get_conn()
                sftp.chdir(self.upload_dir)
                filename = os.path.basename(local_file)
                sftp.put(local_file) # /root/project/lms_jpm/static/files/xxx_request.csv
                logger.info(f"SFTPClient Successfully upload file={filename} to remote_path={self.upload_dir}")
                return True
            except Exception as e:
                logger.error(f"SFTPClient Failed upload file={local_file}, attempt {attempt+1} error={e}")
                if attempt < self.max_retries-1:
                    logger.error(f"SFTPClient Retrying upload file={local_file}, seconds ...")
                    time.sleep(self.retry_delay)
        return False

    def search_file(self, file):
        logger.info(f"SFTPClient start search remote_path={self.download_dir}/{file} ...")
        for attempt in range(self.max_retries):
            try:
                self.ensure_connected()
                self.conn.chdir(self.download_dir)
                files = self.conn.listdir()
                # logger.info(f"----------listdir-----------------{self.download_dir}---------------------------")
                # logger.info(f"-------------------------{file}---------------------{attempt+1}--------------------")
                # logger.info(files)
                # logger.info("--------------------------------------------------------------------")
                # logger.info("--------------------------------------------------------------------")
                # logger.info("--------------------------------------------------------------------")
                if file in files:
                    # logger.info(f"SFTPClient search remote_path={self.download_dir}/{file} ****** find ******")
                    return True
                return False
            except Exception as e:
                logger.error(f"SFTPClient search failed remote_path={self.download_dir}/{file}"+
                    f", attempt= {attempt+1}, error={e}")
                if attempt < self.max_retries-1:
                    time.sleep(self.retry_delay)
        return False

    def download_file(self, file, local_path):
        logger.info(f"SFTPClient start download remote_file={file} to {local_path}")
        for attempt in range(self.max_retries):
            try:
                if not self.ensure_connected():
                    continue
                sftp=self.pool.get_conn()
                sftp.chdir(self.download_dir)
                sftp.get(file, local_path)
                logger.info(f"SFTPClient Successfully downloaded {file} to {local_path}")
                return True
            except Exception as e:
                logger.error(f"SFTPClient Download failed remote_file={file}, attempt= {attempt+1}, error={e}")
                if attempt < self.max_retries-1:
                    time.sleep(self.retry_delay)
                    if os.path.exists(f"{local_path}/{file}"):
                        os.remove(f"{local_path}/{file}")  # 删除可能的部分下载文件
        return False

016-pysftp SFTP

pysftp SFTP

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

import pysftp
import os
import sys
import time
import gnupg

from etc import config
import utils
from utils import logger_web
from utils import logger_lms as logger


# -----------------------------
broker=config.LMS["broker"]
notifier_list=config.Notifier
notifier_list2=config.Notifier2
# -----------------------------

class SFTPClient:
    def __init__(self, host,port, username, password, upload_dir, download_dir,gpg_key_id='D7B7817A'):
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.upload_dir = upload_dir
        self.download_dir = download_dir
        self.sftp = None
        self.gpg = gnupg.GPG(gnupghome="/root/.gnupg")
        self.gpg_key_id=gpg_key_id
        self.max_retries = 3
        self.retry_delay = 5
        # 禁用主机密钥检查
        self.cnopts = pysftp.CnOpts()
        self.cnopts.hostkeys = None
        self.connect()

    def ensure_connected(self):
        """确保SFTP连接是活跃的,如果断开则重连"""
        try:
            self.sftp.listdir()
        except Exception as e:
            logger.error("SFTPClient connection check failed, error={}".format(e))
            self.connect()
            time.sleep(3)

    def connect(self):
        """建立SFTP连接,包含重试机制"""
        for attempt in range(self.max_retries):
            try:
                if self.sftp:
                    try:
                        self.sftp.close()
                    except Exception as e:
                        logger.error("SFTPClient during disconnect error: {}".format(e))
                self.sftp = pysftp.Connection(
                    host=self.host,
                    port=self.port,
                    username=self.username,
                    password=self.password,
                    cnopts=self.cnopts
                )
                logger.info("SFTPClient connected to {}, connected success ...".format(self.host))
                return True
            except Exception as e:
                logger.error("SFTPClient connection attempt {} failed, error={}".format(attempt+1, e))
                if attempt < self.max_retries-1:
                    logger.error("SFTPClient Retrying in {} seconds...".format(self.retry_delay))
                    time.sleep(self.retry_delay)
        return False

    def upload_file(self, local_path):
        logger.info("SFTPClient start upload file={} to remote_path={}".format(local_path, self.upload_dir))
        if not os.path.exists(local_path):
            logger.error("SFTPClient UploadFile ={} does not exist".format(local_path))
            return False

        for attempt in range(self.max_retries):
            try:
                self.ensure_connected()
                self.sftp.chdir(self.upload_dir)
                filename = os.path.basename(local_path)
                self.sftp.put(local_path)
                logger.info("SFTPClient Successfully upload file={} to remote_path={}".format(filename, self.upload_dir))
                self.close()
                utils.send_message('markdown', "{} SFTP upload_file".format(broker),
                           "## {} SFTP upload_file success\nFtpSide={}\nFtpUser={}\nfile={}\n".format(broker,
                            config.LMS['ftp_url'],config.LMS['ftp_user'],filename),notifier_list)
                local_csvfile=local_path.replace(".pgp",'')
                utils.weichat_send_file(local_csvfile)
                return True
            except Exception as e:
                logger.error("SFTPClient Failed upload file={}, attempt {} error={}".format(local_path, attempt+1, str(e)))
                if attempt < self.max_retries-1:
                    logger.error("SFTPClient Retrying upload file={}, seconds...".format(local_path))
                    time.sleep(self.retry_delay)
        return False

    def search_file(self, filename):
        logger.info("SFTPClient start search remote_path={}/{} ...".format(self.download_dir, filename))
        for attempt in range(self.max_retries):
            try:
                self.ensure_connected()
                self.sftp.chdir(self.download_dir)
                files = self.sftp.listdir()
                logger.info(f"----------listdir-----------------{self.download_dir}---------------------------")
                logger.info(f"-------------------------{filename}---------------------{attempt+1}--------------------")
                logger.info(files)
                logger.info("--------------------------------------------------------------------")
                logger.info("--------------------------------------------------------------------")
                logger.info("--------------------------------------------------------------------")
                if filename in files:
                    logger.info("SFTPClient search remote_path={}/{} ****** find ******".format(self.download_dir, filename))
                    return True
                return False
            except Exception as e:
                logger.error("SFTPClient search failed remote_path={}/{}, attempt {}, error={}".format(
                    self.download_dir, filename, attempt+1, str(e)))
                if attempt < self.max_retries-1:
                    time.sleep(self.retry_delay)
        return False

    def download_file(self, remote_filename, local_file):
        logger.info("SFTPClient start download remote_path={}/{} to {}".format(
            self.download_dir, remote_filename, local_file))
        for attempt in range(self.max_retries):
            try:
                self.ensure_connected()
                self.sftp.chdir(self.download_dir)
                self.sftp.get(remote_filename, local_file)
                logger.info("SFTPClient Successfully downloaded {} to {}".format(remote_filename, local_file))
                self.close()
                utils.send_message('markdown', "{} SFTP download_file".format(broker),
                           "## {} SFTP download_file success\nFtpSide={}\nFtpUser={}\nfile={}\n".format(broker,
                            config.LMS['ftp_url'],config.LMS['ftp_user'],remote_filename),notifier_list)
                return True
            except Exception as e:
                logger.error("SFTPClient Download failed remote_path={}/{}, attempt {}, error={}".format(
                    self.download_dir, remote_filename, attempt+1, str(e)))
                if attempt < self.max_retries-1:
                    time.sleep(self.retry_delay)
                    if os.path.exists(local_file):
                        try:
                            os.remove(local_file)  # 删除可能的部分下载文件
                        except Exception as e:
                            logger.error("SFTPClient Download failed remote_path={}/{}, remove partial download local_path={}, error={}".format(
                                self.download_dir, remote_filename, local_file, str(e)))
        return False

    def close(self):
        if self.sftp:
            try:
                self.sftp.close()
            except Exception as e:
                logger.error("SFTPClient close has error:{}".format(e))

009-C++标准库中的<algorithm>头文件提供的常用算法

Cpp标准库中的头文件提供的常用算法

1: 介绍

  • 在 c++中, <algorithm> 头文件提供了一系列用于操作序列(如 array,vector,列表 list)的算法;
  • 这些算法可以极大的帮助我们简单高效的处理数据,提高代码的可读性和可维护性;

2: 查找算法 search

2.1 std::find

  • std::find 是一个线性查找算法,用于在序列中查找特定元素;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <algorithm>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    int val = 3;

    // 使用std::find查找val在vec中的位置
    auto it = std::find(vec.begin(), vec.end(), val);
    if (it != vec.end()) {
        std::cout << "找到元素 " << val << " 在位置 " << std::distance(vec.begin(), it) << std::endl;
    } else {
        std::cout << "未找到元素 " << val << std::endl;
    }
    return 0;
}

2.2 std::find_if

  • std::find_if 允许你根据特定条件在序列中查找元素;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#include <algorithm>
#include <vector>
#include <iostream>

bool is_even(int i) {
    return (i % 2) == 0;
}

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 使用std::find_if查找第一个偶数元素
    auto it = std::find_if(vec.begin(), vec.end(), is_even);

    if (it != vec.end()) {
        std::cout << "找到第一个偶数 " << *it << " 在位置 " << std::distance(vec.begin(), it) << std::endl;
    } else {
        std::cout << "未找到偶数" << std::endl;
    }
    return 0;
}

3: 排序算法 sort

3.1 std::sort

  • std::sort 是一个高效的排序算法,通常实现为快速排序、堆排序或归并排序的混合体;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <algorithm>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {5, 2, 3, 1, 4};

    // 使用std::sort对vec进行排序
    std::sort(vec.begin(), vec.end());

    // 输出排序后的向量
    for (int i : vec) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    return 0;
}

3.2 std::stable_sort

  • std::stable_sort 是一种稳定的排序算法,即相等元素的相对顺序在排序后保持不变;
  • std::stable_sort 用法与 std::sort 类似,但保证排序的稳定性。

4: 修改序列算法

4.1 std::for_each

  • std::for_each 用于对序列中的每个元素执行特定操作;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <algorithm>
#include <vector>
#include <iostream>

void print(int i) {
    std::cout << i << " ";
}

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};

    // 使用std::for_each打印vec中的每个元素
    std::for_each(vec.begin(), vec.end(), print);
    std::cout << std::endl;
    return 0;
}

4.1 std::transform

  • std::transform 用于对序列中的每个元素执行某种转换,并将结果存储到另一个序列中;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <algorithm>
#include <vector>
#include <iostream>
#include <functional> // 为了使用std::plus等函数对象

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::vector<int> result(vec.size());

    // 使用std::transform将vec中的每个元素加倍并存储到result中
    std::transform(vec.begin(), vec.end(), result.begin(), [](int x) { return x * 2; });

    // 输出转换后的结果向量
    for (int i : result) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    return 0;
}

5: 其他常见算法

5.1 std::unique_copy

  • std::unique_copy算法用于从一个输入序列中复制不重复的元素到一个输出序列。这个算法假定输入序列是已排序的,因为只有已排序的序列才能保证相邻的重复元素被识别并去除
  • 先排序;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>

int main() {
    std::vector<int> source = {1, 2, 2, 3, 4, 4, 4, 5};
    std::vector<int> destination;

    // 注意:在这个例子中,std::back_inserter是一个插入迭代器,它将新元素添加到destination容器的末尾
    std::unique_copy(source.begin(), source.end(), std::back_inserter(destination));

    // 输出目标向量,应不包含重复的元素
    for (int val : destination) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    return 0;
}

5.2 std::merge

  • std::merge 算法用于合并两个已排序的序列,结果也是一个已排序的序列;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>

int main() {
    std::vector<int> vec1 = {1, 3, 5, 7};
    std::vector<int> vec2 = {2, 4, 6, 8};
    std::vector<int> result(vec1.size() + vec2.size());

    std::merge(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), result.begin());

    // 输出合并后的结果向量
    for (int val : result) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    return 0;
}

5.3 集合算法:std::set_difference, std::set_intersection, std::set_union, std::set_symmetric_difference

  • 这些算法用于在两个已排序的序列之间执行集合操作。
  • std::set_difference:计算两个已排序范围的差集。
  • std::set_intersection:计算两个已排序范围的交集。
  • std::set_union:计算两个已排序范围的并集。
  • std::set_symmetric_difference:计算两个已排序范围的对称差集(即属于第一个范围但不属于第二个范围,以及属于第二个范围但不属于第一个范围的所有元素)。
  • 对于其他集合算法,使用方法是类似的,只是调用的函数名不同,以及它们处理集合运算的方式不同。这些算法在处理大量数据时可以显著提高效率,因为它们都利用了输入数据已排序的特性来优化性能

6 其他值得注意的算法

  • 除了之前提到的算法外,C++标准库还提供了许多其他有用的算法,这些算法在处理各种编程任务时都非常实用。

6.1. std::partition 和 std::stable_partition

std::partition 和 std::stable_partition 算法用于根据给定谓词对序列进行划分,使得满足谓词的元素出现在不满足谓词的元素之前。std::stable_partition 还保持了等价元素的相对顺序。