PSP - 蛋白质序列搜索算法 MMseqs2 与 HHblits 的搜索结果差异

news2024/9/20 8:01:38

欢迎关注我的CSDN:https://spike.blog.csdn.net/
本文地址:https://spike.blog.csdn.net/article/details/132025401

BFD

在 AlphaFold2 中,使用 HHblits 算法搜索 BFD 与 UniRef30,输出 bfd_uniref_hits.a3m 文件。MMseqs2 优化搜索速度之后,比较使用 MMseqs2 算法与 HHblits 算法之间,BFD 与 UniRef30的搜索结果差异。

构建 MMseqs2 搜索库使用 ffindex2fasta 工具 (来源于 MMseqs v1),将 BFDUniRef30 转换成 fasta 文件,即:

$MMDIR/bin/ffindex2fasta resultDB resultDB.fasta

转换之后 BFD 是 1.5T,UniRef30 是 160G。

测试 Case 来源于 CASP15,即:T1104-D1_A117.fastaT1137s8-D1_A251.fastaT1188-D1_A573.fastaT1157s1_A1029.fasta,序列长度100、250、500、1000等。


1. AF2 MSA

bfd_uniref_hits.a3m中序列数量,一般而言,序列越长,可搜索出的序列数量越多,即:

  • T1104-D1_A117: 333 (包括自己)
  • T1137s8-D1_A251:1687
  • T1188-D1_A573:3648
  • T1157s1_A1029:3383

即,来自于 HHblits 搜索的日志 wc -l

666 bfd_uniref_hits.a3m			# T1104-D1_A117
3374 bfd_uniref_hits.a3m		# T1137s8-D1_A251
7296 bfd_uniref_hits.a3m		# T1188-D1_A573
6766 bfd_uniref_hits.a3m		# T1157s1_A1029

其中, T1104-D1_A117bfd_uniref_hits.a3m 数据如下,一部分来自BFD,一部分来自UniRef30,即:

>A
QLEDSEVEAVAKGLEEMYANGVTEDNFKNYVKNNFAQQEISSVEEELNVNISDSCVANKIKDEFFAMISISAIVKAAQKKAWKELAVTVLRFAKANGLKTNAIIVAGQLALWAVQCG
>tr|A0A256LDH3|A0A256LDH3_9LACO Streptococcin A-M57 OS=Lactobacillus taiwanensis GN=CBF70_06415 PE=4 SV=1
VDNDPEVAVVAQELEKIFANGVSQENLNRYVLKNFSNKELTVAEKELDVNYNPFslqskndnnslhsvsvygwnnlgqCMYNKIKDEFFAMVNIGVIVKYAKKKAWKELAKVVIRFAKGAGVRTNAAIVAAQLAVWAVQCG
>tr|F7SG70|F7SG70_LACJH Uncharacterized protein OS=Lactobacillus johnsonii pf01 GN=PF01_01547 PE=4 SV=1
VDNDPEVAIAAQELEKIFVDVVSQKNLNRYALKNFSNKELTVAEKELDVNYNPFslqlkndnnslhsvsvyg---------------------------------------------------------------
>tr|Q6DRR6|Q6DRR6_STRPY Streptococcin A-M57 OS=Streptococcus pyogenes GN=scnM57 PE=4 SV=1
IEEQRQIDEVAAVLEKMFADGVTEENLKQYAQANYSEEELIIADNELNTNLSQIqdenaimykvdwgalgnCMANKIKDELLAMISVGTIIKYAQKKAWKELAKIVIKYVAKAGVKTNAALIAGQLAIWGLQCG
>tr|A0A1C0USB4|A0A1C0USB4_STREE Streptococcin A-M57 OS=Streptococcus pneumoniae GN=A4260_03625 PE=4 SV=1
TQEQKQIDDVANVLEQMFRNGVNEKNFTEYVYKNFSQKDIALAENELETNINNPydrvpwdemggCIAGKIRDEFFAMINVSLIVKYAQKKAWSELAKVVLRFVKANGLKTNIYIIAGQLAIWAVQCG
>tr|A0A133S201|A0A133S201_STRMT Uncharacterized protein OS=Streptococcus mitis GN=HMPREF3228_00364 PE=4 SV=1
----------------MFRNGVNEKNFTECVYKNFSQKDIALAENKLETNINNLydrvpwdemggCIARKIREEFFAMTNVSLTVRYA----------------------------------------
>tr|R2N7C7|R2N7C7_ENTFC Uncharacterized protein OS=Enterococcus faecium EnGen0191 GN=SSI_02965 PE=4 SV=1
QIKNSEVDTVAQGLEQMFSNGVSEENFKNYVNANFSSEEITKSEKELDVNLSNTsspiqarvnwnglgqCMANKIKDEFFAMINVGAIVAAAQKKAWKELAMTVLIFAKANGLKTNALIVAGQLAVWAVQCG
>UniRef100_A0A2N8LAA9 Uncharacterized protein n=1 Tax=Streptococcus penaeicida TaxID=1765960 RepID=A0A2N8LAA9_9STRE
-ISQSEVDAVAIEFEKLFSNGIiiSGNNYSinyDYLNNNYTSEEIQAFINLMASSELSPissgrrkrsissfvvCMKDKAVSDIADMFKVSAFVSFVQRKAWKEAAKFAVSWLAKNGIKRNVAATAALLSWYGIQCA
>UniRef100_A0A2X3SLP5 Uncharacterized protein n=2 Tax=Streptococcus equi TaxID=1336 RepID=A0A2X3SLP5_STRSZ
-TNtsSQEVDQVAQALELMFDNNVSTSNFKKYVNNNFSDSEIAIAELELESRISNSrsefrvawnemggCIAGKIRDEFFAMISVGTIVKYAQKKAWKELALVVLKFVKANGLKTNAIIVAGQLALWAVQCG
>UniRef100_A0A2X4H7F6 Uncharacterized protein n=4 Tax=Streptococcus uberis TaxID=1349 RepID=A0A2X4H7F6_STRUB
-VSQTEIESVASEFEQLFTKGIiiSGNNYTfnhDYLTNNYTSDEIQAFIHLMDSTDLSPtfskrrkrsigsfavCMKDKAVSDIADMFKVGAFVSFVQRKAWKEAAKFAVSWLAKNGIKRNVAATAALLSWYGIQCA

其中,tr 开头的来自于 BFD,UniRef100 开头的来自于 UniRef30

具体而言:

  • >UniRef100 是 250 条,UniRef30
  • >tr| + >SRR 是 81 条,BFD
  • 其他 1 条,BFD
  • 合计 332 条

序列示例如下:

>UniRef100_A0A2W5AUB7 Uncharacterized protein n=1 Tax=Streptococcus pyogenes TaxID=1314 RepID=A0A2W5AUB7_STRPY
-----------------------------MIGDLLKSKEVLLKKTARQTSLSQiQdddvimyktdwnalgsCMANKIKDELLAMISIGTIITYAKRKAWKELATIVIKYVAKAGVRTHAAFIAGQLAIWGLQCG
>SoimicmetaTmtLPB_FD_contig_61_1212631_length_209_multi_1_in_0_out_0_1 # 2 # 76 # 1 # ID=3042713_1;partial=10;start_type=Edge;rbs_motif=None;rbs_spacer=None;gc_cont=0.693
---NEEIEQLAADLEFLMEEAAiydEKGKVVnfdfDLLEERFgYVLELEMLKEEIEAYnattegd--NDeiqlfswksCMISALKGHFGvALIEValtGGLWSYLEKKAYKEAAKLLLKI----GIEGNVIGLTAFLTWYSVDCI
>tr|Q4V1Z0|Q4V1Z0_BACCZ Uncharacterized protein OS=Bacillus cereus (strain ZK / E33L) GN=pE33L466_0102 PE=4 SV=1
-----LVQAVAAQLKFVVEEAAvkdKHGRVVdiDMIENKYgKTEELEQLRQEIQRVNTPPgyedpfkqeteavgnCIERKLIANYVEVLSVgflGSIIANITNKEYELAARKMIKL----GVKGNLISLAGQLAWYLGTCI
>SRR5690606_14355373 
-----QIEELAAQLEFLMEEALiiENGERTfdfEKIENEFgkeVKDEIKMLTVDAQVWqvqpgaitlaanqPWKDCMVGAIKDHFGvALVTAaleGGLWAYLEKKAYKEAAKLLVKF----AVGTNAVGIAGTLIYYGGKCT

结论:在T1104-D1_A117bfd_uniref_hits.a3m 数据中,UniRef30 的搜索数量略大于 BFD,与数据库大小相反。

BFD (Big Fantastic Database) 是由 Martin Steinegger 博士构建的大型蛋白质序列数据库,包含超过 65 亿个蛋白质家族和 220 亿个蛋白质序列,覆盖了多种来源的蛋白质数据,如 UniProt、Metaclust、SRC 和 MERC。BFD 蛋白质数据库的目的是为了提供一个高质量、高覆盖率、低冗余的蛋白质序列资源,用于蛋白质结构预测、功能注释、进化分析等领域。

BFD 蛋白质数据库的构建过程是这样的:

  1. 从三大序列库 (GenBank \ EMBL \ DDBJ) 中采集 24 亿条蛋白质序列,使用 MMSeqs2 / Linclust 工具进行聚类,根据序列相似度和排列覆盖率的标准,将相似的序列归为一个家族,并且选取一个代表序列。
  2. 从 Metaclust 序列库中,补充了一些较长的序列,与已有的代表序列进行比对,将满足条件的序列加入相应的家族,将不满足条件的序列单独聚类。
  3. 对每个家族进行多序列比对 (MSA) 和隐马尔可夫模型 (HMM) 的构建,得到 BFD 蛋白质数据库。

2. MMseqs2 MSA

测试 BFD 脚本:

bash mmseqs2_search.sh test_fasta/T1104-D1_A117.fasta test_fasta/T1104-D1_A117-bfd-i3s8.a3m msa_databases/af2_msa_mmseqs/bfd_mmseqs/bfd_db 3 8 T1104-D1_A117-bfd-i3s8

测试效果:

[Info] Time taken to execute commands is 1974 seconds. (32.9 min)
154 test_fasta/T1104-D1_A117-bfd-i3s8.a3m

测试 UniRef30 脚本:

bash mmseqs2_search.sh test_fasta/T1104-D1_A117.fasta test_fasta/T1104-D1_A117-uniref30-i3s8.a3m msa_databases/af2_msa_mmseqs/uniref30_mmseqs/uniref30_db 3 8 T1104-D1_A117-uniref30-i3s8

测试效果:

[Info] Time taken to execute commands is 1266 seconds.
194 test_fasta/T1104-D1_A117-uniref30-i3s8.a3m

测试脚本:

# params
#=========================================
mmseqs=mmseqs
tmp=tmp_my
query_fasta=$1		# fasta
a3m_db=$2			# MSA
target_db=$3		# DB Path
num_iterations=$4   # 迭代轮次
sensitivity=$5		# 敏感度
out_tag=$6          # 唯一标识, 避免多进程搜索干扰

target_db_index=${target_db}.idx

query_db=$tmp/${out_tag}_queryDB
result_db=$tmp/${out_tag}_res  # 文件
result_db_realign=$tmp/${out_tag}_res_realign
result_db_realign_filter=$tmp/${out_tag}_res_realign_filter
tmp_db=$tmp/${out_tag}_tmp

#=========================================
echo "[Info] query_fasta: $1"
echo "[Info] a3m_db: $2"
echo "[Info] target_db: $3"
echo "[Info] num_iterations: $4"
echo "[Info] sensitivity: $5"
echo "[Info] out_tag: $6"

mkdir -p $tmp

time_start=$(date +%s)
#=========================================

$mmseqs createdb ${query_fasta} ${query_db}
#$mmseqs search ${query_db} ${target_db} ${result_db} ${tmp_db} --db-load-mode 2 --num-iterations ${num_iterations} -s ${sensitivity} --max-seqs 10000 -e 0.1 -a --threads 16 --mpi-runner "mpirun --allow-run-as-root -np 8"
$mmseqs search ${query_db} ${target_db} ${result_db} ${tmp_db} --db-load-mode 2 --num-iterations ${num_iterations} -s ${sensitivity} --max-seqs 10000 -e 0.1 -a --threads 16
$mmseqs align ${query_db} ${target_db_index} ${result_db} ${result_db_realign} --db-load-mode 2 -e 10 --max-accept 100000 --alt-ali 10 -a --threads 16
$mmseqs filterresult ${query_db} ${target_db_index} ${result_db_realign} ${result_db_realign_filter} --db-load-mode 2 --qid 0 --qsc 0.8 --diff 0 --max-seq-id 1.0 --filter-min-enable 100 --threads 16
$mmseqs result2msa ${query_db} ${target_db_index} ${result_db_realign_filter} ${a3m_db} --msa-format-mode 6 --db-load-mode 2 --filter-msa 1 --filter-min-enable 1000 --diff 3000 --qid 0.0,0.2,0.4,0.6,0.8,1.0 --qsc 0 --max-seq-id 0.95 --threads 16

$mmseqs rmdb ${result_db_realign_filter}
$mmseqs rmdb ${result_db}
$mmseqs rmdb ${result_db_realign}

#=========================================
time_end=$(date +%s)
time_take=$(( time_end - time_start ))

echo "[Info] MMseqs2 path is ${mmseqs} ."
echo "[Info] Time taken to execute commands is ${time_take} seconds."

参数网格搜索的多进程脚本:

#!/usr/bin/env python
# -- coding: utf-8 --
"""
Copyright (c) 2022. All rights reserved.
Created by C. L. Wang on 2023/7/31
"""

import os
import subprocess
import sys
from multiprocessing import Pool
from time import time

from tqdm import tqdm

p = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if p not in sys.path:
    sys.path.append(p)

from myutils.project_utils import mkdir_if_not_exist, traverse_dir_files, time_elapsed, create_empty_file
from root_dir import ROOT_DIR, DATA_DIR


def process(params):
    """
    单进程
    """
    sh_file, fasta_path, output_path, db_path, i_idx, s_idx, out_name = params
    # 输出文件
    s_time = time()
    res = subprocess.check_output([
        "bash", sh_file,
        fasta_path,
        output_path,
        db_path,
        str(i_idx),
        str(s_idx),
        out_name,  # 用于缓存临时文件
    ], shell=False)
    # print(f"[Info] res: \n{res.decode()}")
    print(f"[Info] time: {time_elapsed(s_time, time())}, output_path: {output_path}")


def main():
    """
    参数网格搜索的脚本
    """
    output_dir = os.path.join(DATA_DIR, "results")
    fasta_dir = os.path.join(ROOT_DIR, "data", "fasta")
    mkdir_if_not_exist(output_dir)
    print(f"[Info] 输出文件夹: {output_dir}")
    print(f"[Info] 输入 fasta 文件夹: {fasta_dir}")
    path_list = traverse_dir_files(fasta_dir, "fasta")
    print(f"[Info] fasta 数量: {len(path_list)}")
    bfd_db = "msa_databases/af2_msa_mmseqs/bfd_mmseqs/bfd_db"
    uniref30_db = "msa_databases/af2_msa_mmseqs/uniref30_mmseqs/uniref30_db"
    sh_file = os.path.join(ROOT_DIR, "search.sh")

    params_list = []
    # 遍历次数 4x2x3x8 = 192
    for fasta_path in path_list:
        base_name = os.path.basename(fasta_path).split(".")[0]
        # print(f"[Info] fasta_path: {fasta_path}")
        output_fasta_dir = os.path.join(output_dir, base_name)
        mkdir_if_not_exist(output_fasta_dir)
        max_i, max_s = 3, 8
        for db in ["bfd", "uniref30"]:
            if db == "bfd":     # 数据库 设置
                db_path = bfd_db
            elif db == "uniref30":
                db_path = uniref30_db
            else:
                raise Exception(f"db name error: {db}")
            for i_idx in range(1, max_i+1):
                for s_idx in range(1, max_s+1):
                    out_name = f"{base_name}-{db}-i{i_idx}s{s_idx}"
                    output_path = os.path.join(output_fasta_dir, f"{out_name}.a3m")
                    create_empty_file(output_path)
                    params_list.append((sh_file, fasta_path, output_path, db_path, i_idx, s_idx, out_name))

    print(f"[Info] 推理次数: {len(params_list)}")

    # 多进程
    n_proc = min(len(params_list), 20)
    pool = Pool(processes=n_proc)
    list(tqdm(pool.imap(process, params_list), desc="[Info] run"))
    pool.close()
    pool.join()

    # 单进程测试
    # for params in tqdm(params_list, desc="[Info] run"):
    #     process(params)

    print("[Info] 全部处理完成!")



if __name__ == '__main__':
    main()

其他

PyCharm 其他版本下载

下载地址:PyCharm - 2022.3

参考

  • CSDN - python执行shell脚本的几种方法
  • GitHub - user guide error and unknown output format
  • GitHub - MMseqs

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Selenium-用这个框架自动化任何你想做的事情!

Chrome DevTools 简介 Chrome DevTools 是一组直接内置在基于 Chromium 的浏览器(如 Chrome、Opera 和 Microsoft Edge)中的工具,用于帮助开发人员调试和研究网站。 借助 Chrome DevTools,开发人员可以更深入地访问网站&#xf…

职责链模式-请求的链式处理

在实际开发中,对于一个请求我们要经过层层过滤:身份验证 -> 权限验证 -> 实际业务处理。请求沿着一个链在传递,每一层都可以处理该请求。而“职责链模式”就是专门用于处理这种请求链式传递的模式。 1 职责链模式概述 避免将请求发送…

Kubernetes系列

文章目录 1 详解docker,踏入容器大门1.1 引言1.2 初始docker1.3 docker安装1.4 docker 卸载1.5 docker 核心概念和底层原理1.5.1 核心概念1.5.2 docker底层原理 1.6 细说docker镜像1.6.1 镜像的常用命令 1.7 docker 容器1.8 docker 容器数据卷1.8.1 直接命令添加1.8.2 Dockerfi…

2023-07-31 C语言根据错误号打印详细的错误信息perror(““) 或者strerror(errno)

一、C 语言可以使用perror("perror output"); 或 strerror(errno)打印详细的错误信息。 二、需要的头文件#include <errno.h>。 三、实例测试&#xff0c;这里我让open一个linux 底层杂项设备失败的情况&#xff0c;返回的是一个负数&#xff0c;强制返回-EN…

【shell】获取ping的时延数据并分析网络情况

网络情况经常让我们头疼&#xff0c;每次都需要手动在终端ping太麻烦了&#xff0c;不如写个脚本ping并将数据带上时间戳存入文件&#xff0c;然后也可以分析哪个时间段网络比较差。 创建一个demo.sh文件&#xff1a; #!/bin/bash # 清理日志 net_path"./network/"…

性能测试必备监控技能windows篇

前言 在手头没有专门的第三方监控时&#xff0c;该怎么监控服务指标呢&#xff1f;本篇就windows下监控进行分享&#xff0c;也是我们在进行性能测试时&#xff0c;必须掌握的。下面我们就windows下常用的三种监视工具进行说明&#xff1a; 任务管理器 资源监视器 性能监视器…

AD21 PCB设计的高级应用(一)BGA的扇出方式

&#xff08;一&#xff09;BGA的扇出方式 1.软件自动扇出方式2.手工扇出方式3.多种规格BGA的出现方式 1.软件自动扇出方式 在进行PCB设计时,常会遇到 BGA类型的封装&#xff0c;此类封装需要扇出用于后期的布线。BGA 扇出与否的比对如图所示。 (1)在进行利用软件自动扇出 BGA…

移动端适配布局rem和vw

在日益发展的移动互联网时代&#xff0c;作为前端开发者&#xff0c;我们必须了解和掌握各种移动端显示效果的适配技术。在众多适配方案中&#xff0c;使用rem和vw进行布局是当前最为流行和普遍使用的两种技术。通过合理运用这两种技术&#xff0c;我们可以让我们的网页在不同尺…

HCIP——前期综合实验

前期综合实验 一、实验拓扑二、实验要求三、实验思路四、实验步骤1、配置接口IP地址2、交换机配置划分vlan10以及vlan203、总部分部&#xff0c;骨干网配置OSPF分部总部骨干网 4、配置BGP建立邻居关系总部骨干网分部 5、发布用户网段6、将下一跳改为本地7、允许AS重复8、重发布…

揭秘!头条百科词条创建全过程及技巧解析

随着互联网时代的到来&#xff0c;人们获取信息的方式越来越便捷。作为国内领先的信息平台&#xff0c;头条百科成为了很多人查阅知识的首选。然而&#xff0c;如何在头条上创建百科词条&#xff0c;让更多人了解和熟知自己呢&#xff1f;本文伯乐网络传媒将为您揭开这个谜团&a…

何恺明把神经网络做深了,谷歌把神经网络的入口拉大了,又深又大,才成为今天的大模型

openai chatgpt 相关_个人渣记录仅为自己搜索用的博客-CSDN博客 大神回归学界&#xff1a;何恺明宣布加入 MIT 如今大模型都在使用的 transformer 的编码器和解码器&#xff0c;里面都有源自 ResNet 的残差链接。 「在 ResNet 之后就可以有效地训练超过百层的深度神经网络&…

Windows 实例如何开放端口

矩池云 Windows 实例相比于 Linux 实例&#xff0c;除了在租用机器的时候自定义端口外&#xff0c;还需要在 Windows防火墙中添加入口规则。接下来将教大家如何设置 Windows 防火墙&#xff0c;启用端口。 租用成功后通过 RDP 链接连接服务器&#xff0c;然后搜索防火墙&#x…

uniapp使用getStorage对属性赋值无效

1正常set(get)storage都是可以正常使用的 2.但对属性进行赋值的时候&#xff0c;却发现this.name并没有发生变化 3. 在里面打印this发现&#xff0c;在set*getStorage中并不能拿到this. 4.优化代码 这样就可以给this.name成功赋值

pinia 状态管理器详细文档记录,如何使用pinia看着一篇就够了!!!

目录 安装Pinia 定义store 1.option对象写法&#xff1a; 2.Setup 函数写法 使用store 接下来细化一下pinia的三大核心概念 state、action、getter 一、state 访问 state 重置 state 变更 state 替换 state 订阅 state 二、Getter 访问其他 getter 向 getter 传递…

116、你是如何理解Spring事务的传播机制的?底层是如何实现的?

你是如何理解Spring事务的传播机制的&#xff1f;底层是如何实现的&#xff1f; 一个线程在运行过程中&#xff0c;可能会连续调用好几个方法&#xff0c;在调用某一个方法时&#xff0c;可能就开启了一个Spring事务&#xff0c;那么在调用接下来的方法时&#xff0c;到底是共用…

【C++】二叉搜索树的原理及实现

简介 二叉搜索树(Binary Search Tree&#xff0c;BST)是一种常用的数据结构&#xff0c;本文将介绍二叉搜索树的原理与特性&#xff0c;并给出C代码实现&#xff0c;最后对其性能进行详细的分析。 文章目录 简介 一、二叉搜索树的概念 二、二叉搜索树的操作及实现 2、1 二叉搜…

01|Oracle学习(监听程序、管理工具、PL/SQL Developer、本地网络服务介绍)

基础概念 监听程序&#xff1a;运行在Oracle服务器端用于侦听客户端请求的程序。 相当于保安&#xff0c;你来找人&#xff0c;他会拦你&#xff0c;问你找谁。他去帮你叫人过来。 配置监听程序应用场景 Oracle数据库软件安装之后没有监听程序&#xff08;服务&#xff09;…

pdf阅读器哪个好用?这个阅读器别错过

pdf阅读器哪个好用&#xff1f;PDF是一种流行的文件格式&#xff0c;可以保留文档的原始格式、布局和字体。与其他文档格式相比&#xff0c;PDF在不同设备和操作系统上的显示效果更为一致&#xff0c;确保文档内容的准确性和可读性。在阅读一些PDF文件的时候&#xff0c;使用一…

文本怎么用手机生成二维码?二维码在线文本码制作技巧

现在二维码可以展示的内容越来越丰富&#xff0c;比如文本就是很常见的一种形式。编辑好文本内容之后&#xff0c;将文字内容添加到二维码中&#xff0c;其他人扫码就可以获取到文字内容&#xff0c;那么文本二维码该如何制作呢&#xff1f;想要制作二维码&#xff0c;那么可以…

全网最牛,postman接口测试-高级应用实战(总结)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 流程控制 流程控…