深度神经网络算子参数量和计算量分析—卷积篇

前言

在用于计算机视觉任务的深度神经网络模型中,卷积算子作为一种重要的特征提取方式被广泛应用,本文针对常见的卷积算子参数量和计算量的计算方法进行分析,主要包括普通卷积、深度可分离卷积、分组卷积,以及自动计算模型参数量和计算量的工具库ptflops进行简单介绍。


文章目录

    • 前言
    • 1. 普通卷积
      • (1) Params
      • (2) FLOPs
    • 2. 深度可分离卷积
      • (1) Params
      • (2) FLOPs
    • 3.分组卷积
      • (1) Params
      • (1) FLOPs
    • 4. ptflops


1. 普通卷积

在这里插入图片描述

对于普通的卷积算子,也就是让卷积核在特征图上按照既定规则进行滑动,并在每一个位置对应元素相乘后累加得到输出特征图的一个像素点。

我们假设输入特征图维度(宽、高、通道数)为 W i × H i × C i W_{i} \times H_{i} \times C_{i} Wi×Hi×Ci,卷积核的维度(宽、高、卷积核个数)为 K w × K h × C i K_{w} \times K_{h} \times C_{i} Kw×Kh×Ci,输出特征图的维度(宽、高、通道数)为 W o × H o × C o W_{o} \times H_{o} \times C_{o} Wo×Ho×Co

(1) Params

单个卷积核权重参数共有 K w × K h × C i K_{w} \times K_{h} \times C_{i} Kw×Kh×Ci偏置参数共有1个,共有 C o C_{o} Co个卷积核,因此,普通卷积算子的参数量为:

P a r a m s = ( K w × K h × C i + 1 ) × C o Params=(K_{w} \times K_{h} \times C_{i} +1) \times C_{o} Params=(Kw×Kh×Ci+1)×Co

(2) FLOPs

对于普通的卷积算子,卷积核在特征图上每滑动一次,将对应元素相乘后累加得到输出特征图中的一个像素点,因此,输出特征图中的一个像素点的计算量为:

( K w × K h × C i ) × ( K w × K h × C i − 1 ) + 1 (K_{w} \times K_{h}\times C_{i}) \times (K_{w} \times K_{h}\times C_{i}-1)+1 (Kw×Kh×Ci)×(Kw×Kh×Ci1)+1

其中 K w × K h × C i K_{w} \times K_{h}\times C_{i} Kw×Kh×Ci是做乘法运算的次数, K w × K h × C i − 1 K_{w} \times K_{h}\times C_{i}-1 Kw×Kh×Ci1是做加法运算的次数, + 1 +1 +1是加偏置运算的加法次数(每次滑动需要一次加偏置操作,或者理解为每一个输出特征像素需要一次加偏置操作)。

输出特征图的维度大小是 W o × H o × C o W_{o} \times H_{o} \times C_{o} Wo×Ho×Co,故对于普通的卷积算子总的计算量为:

F L O P s = [ ( K w × K h × C i ) × ( K w × K h × C i − 1 ) + 1 ] × W o × H o × C o = 2 × K w × K h × C i × W o × H o × C o FLOPs=[(K_{w} \times K_{h}\times C_{i}) \times (K_{w} \times K_{h}\times C_{i}-1)+1]\times W_{o} \times H_{o} \times C_{o}\\ = 2\times K_{w} \times K_{h} \times C_{i} \times W_{o} \times H_{o} \times C_{o} FLOPs=[(Kw×Kh×Ci)×(Kw×Kh×Ci1)+1]×Wo×Ho×Co=2×Kw×Kh×Ci×Wo×Ho×Co

2. 深度可分离卷积

在这里插入图片描述

对于深度可分离卷积算子,其主要由两部分操作组成,即深度卷积(上图Depthwise Convolution)和点卷积(上图Pointwise Convolution),深度卷积也叫逐通道卷积,具体实现为:对于输入特征图的每一个通道,都有一个对应的卷积核去和它做卷积运算,最后得到的特征图通道数和输入特征图通道数相同。点卷积即使用 1 × 1 1\times1 1×1大小的卷积核对特征图做普通卷积。

我们假设输入特征图的维度(宽、高、通道数)为 W i × H i × C i W_{i} \times H_{i}\times C_{i} Wi×Hi×Ci,深度可分离卷积中的深度卷积维度(宽、高、卷积核个数)为 K w × K h × C i K_{w} \times K_{h}\times C_{i} Kw×Kh×Ci,经过深度卷积后的维度(宽、高、通道数)为 W m × H m × C i W_{m} \times H_{m} \times C_{i} Wm×Hm×Ci,深度可分离卷积中的点卷积维度(宽、高、卷积核通道数卷积核个数)为 1 × 1 × C i × C o 1 \times 1 \times C_{i} \times C_{o} 1×1×Ci×Co,输出特征图的维度(宽、高、通道数)为 W o × H o × C o W_{o} \times H_{o}\times C_{o} Wo×Ho×Co

我们再对照着上面的假设理解一次深度可分离卷积的过程,首先对于 W i × H i × C i W_{i} \times H_{i}\times C_{i} Wi×Hi×Ci输入特征图进行深度卷积,即逐通道 W i × H i W_{i} \times H_{i} Wi×Hi和深度卷积核 K w × K h K_{w} \times K_{h} Kw×Kh进行卷积运算然后生成一张特征图,输入特征图的通道数和深度卷积核的个数都为于 C i C_{i} Ci,故深度卷积共有 C i C_{i} Ci张输出特征图,然后对深度卷积得到的 C i C_{i} Ci张输出特征图进行点卷积(普通卷积),即每一个点卷积核 1 × 1 × C i 1 \times 1 \times C_{i} 1×1×Ci和深度卷积得到的 C i C_{i} Ci张输出特征图进行普通卷积得到一张 W o × H o W_{o} \times H_{o} Wo×Ho的特征图,而点卷积的个数共有 C o C_{o} Co 个,故输出特征图维度为 W o × H o × C o W_{o} \times H_{o}\times C_{o} Wo×Ho×Co

理解其过程后,下面我们分析深度可分离卷积算子的参数量和计算量

(1) Params

对于深度卷积,单个卷积核的维度大小(宽、高、卷积核通道)为 K w × K h × 1 K_{w} \times K_{h}\times 1 Kw×Kh×1偏置参数共有1个, 共有 C i C_{i} Ci个深度卷积核,故其参数量为:

P a r a m s 深度卷积 = ( K w × K h × 1 + 1 ) × C i Params_{深度卷积} = (K_{w} \times K_{h} \times1+1) \times C_{i} Params深度卷积=(Kw×Kh×1+1)×Ci

对于点卷积,单个卷积核的维度大小(宽、高、卷积核通道)为 1 × 1 × C i 1 \times 1 \times C_{i} 1×1×Ci偏置参数共有1个, 共有 C o C_{o} Co个深度卷积核,故其参数量为:

P a r a m s 点卷积 = ( 1 × 1 × C i + 1 ) × C o Params_{点卷积} = (1 \times 1 \times C_{i}+1) \times C_{o} Params点卷积=(1×1×Ci+1)×Co

故,对于深度可分离卷积来说,其总的参数量为:

P a r a m s = P a r a m s 深度卷积 + P a r a m s 点卷积 = [ ( K w × K h + 1 ) × C i ] + [ ( 1 × 1 × C i + 1 ) × C o ] Params=Params_{深度卷积}+Params_{点卷积} =[(K_{w} \times K_{h}+1) \times C_{i}] + [(1 \times 1 \times C_{i}+1) \times C_{o}] Params=Params深度卷积+Params点卷积=[(Kw×Kh+1)×Ci]+[(1×1×Ci+1)×Co]

(2) FLOPs

对于深度卷积,同样的深度卷积核在特征图上每滑动一次,将对应元素相乘后累加得到输出特征图中的一个像素点,因此,输出特征图中的一个像素点的计算量为:

( K w × K h × 1 ) × ( K w × K h × 1 − 1 ) + 1 (K_{w} \times K_{h} \times1) \times (K_{w} \times K_{h} \times 1-1)+1 (Kw×Kh×1)×(Kw×Kh×11)+1

其中 K w × K h × 1 K_{w} \times K_{h} \times1 Kw×Kh×1是做乘法运算的次数, K w × K h × 1 − 1 K_{w} \times K_{h} \times1-1 Kw×Kh×11是做加法运算的次数, + 1 +1 +1是加偏置运算的加法次数(每次滑动需要一次加偏置操作,或者理解为每一个输出特征像素需要一次加偏置操作)。

注意:这里的 × 1 \times 1 ×1表示卷积核通道数,因为是逐通道卷积,也就是通道数为1的卷积运算。

深度卷积输出特征图的维度大小是 W m × H m × C i W_{m} \times H_{m}\times C_{i} Wm×Hm×Ci,故对于深度卷积算子总的计算量为:

F L O P s 深度卷积 = [ ( K w × K h ) × ( K w × K h − 1 ) + 1 ] × W m × H m × C i = 2 ⋅ ( K w × K h ) × W m × H m × C i FLOPs_{深度卷积} =[(K_{w} \times K_{h}) \times (K_{w} \times K_{h}-1)+1]\times W_{m} \times H_{m}\times C_{i}\\=2\cdot (K_{w} \times K_{h})\times W_{m} \times H_{m}\times C_{i} FLOPs深度卷积=[(Kw×Kh)×(Kw×Kh1)+1]×Wm×Hm×Ci=2(Kw×Kh)×Wm×Hm×Ci

对于点卷积,同样的点卷积核在特征图上每滑动一次,将对应元素相乘后累加得到输出特征图中的一个像素点,因此,输出特征图中的一个像素点的计算量为:

( 1 × 1 × C i ) × ( 1 × 1 × C i − 1 ) + 1 (1 \times 1 \times C_{i}) \times (1 \times 1 \times C_{i}-1)+1 (1×1×Ci)×(1×1×Ci1)+1

其中 1 × 1 × C i 1 \times 1 \times C_{i} 1×1×Ci是做乘法运算的次数, 1 × 1 × C i − 1 1 \times 1 \times C_{i}-1 1×1×Ci1是做加法运算的次数, + 1 +1 +1是加偏置运算的加法次数(每次滑动需要一次加偏置操作,或者理解为每一个输出特征像素需要一次加偏置操作)。

点卷积输出特征图的维度大小是 W o × H o × C o W_{o} \times H_{o}\times C_{o} Wo×Ho×Co,故对于点卷积算子总的计算量为:

F L O P s 点卷积 = [ ( 1 × 1 × C i ) × ( 1 × 1 × C i − 1 ) + 1 ] × W o × H o × C o = 2 ⋅ C i × W o × H o × C o FLOPs_{点卷积} =[(1 \times 1 \times C_{i}) \times (1 \times 1 \times C_{i}-1)+1] \times W_{o} \times H_{o}\times C_{o}\\ =2\cdot C_{i}\times W_{o} \times H_{o}\times C_{o} FLOPs点卷积=[(1×1×Ci)×(1×1×Ci1)+1]×Wo×Ho×Co=2Ci×Wo×Ho×Co

故对于深度可分离卷积来说,其总的计算量为:

F L O P s = F L O P s 深度卷积 + F L O P s 点卷积 = [ 2 ⋅ ( K w × K h ) × W m × H m × C i ] + [ 2 ⋅ C i × W o × H o × C o ] FLOPs=FLOPs_{深度卷积}+FLOPs_{点卷积} =[2\cdot (K_{w} \times K_{h})\times W_{m} \times H_{m}\times C_{i}] + [2\cdot C_{i}\times W_{o} \times H_{o}\times C_{o}] FLOPs=FLOPs深度卷积+FLOPs点卷积=[2(Kw×Kh)×Wm×Hm×Ci]+[2Ci×Wo×Ho×Co]

3.分组卷积

在这里插入图片描述

分组卷积是卷积神经网络中常用的一种卷积操作,它将输入的特征图分成若干组,每组特征图分别与对应的卷积核进行卷积操作,然后将各组的卷积结果拼接在一起形成最终的输出特征图。上图左边是普通卷积的示意图,右图是分组卷积的示意图,下面大概介绍一下分组卷积的基本流程:

  1. 输入特征图分组:将输入特征图按照通道数分成若干组,每组包含相等数量的通道。
  2. 分组卷积核:为每个分组准备对应的卷积核,每个卷积核组的数量与输入特征图的分组数量相同。
  3. 分组卷积操作:对每个分组的输入特征图分别使用对应的分组卷积核进行卷积操作,得到各组的卷积结果。
  4. 输出特征图拼接:将各组的卷积结果按照通道顺序进行拼接,形成最终的输出特征图。

分组卷积的主要优势在于可以减少参数量和计算量,同时提高模型的并行性,特别适用于计算资源有限的场景。这种技术在一些轻量级的神经网络结构中得到了广泛的应用。

我们假设分组卷积的分组数为 g g g组,输入特征图的维度(宽、高、通道数)为 W i × H i × C i W_{i} \times H_{i}\times C_{i} Wi×Hi×Ci,那么每一组输入特征图的维度(宽、高、通道数)为 W i × H i × C i g W_{i} \times H_{i} \times \frac{C_{i}}{g} Wi×Hi×gCi,共有 g g g组输入特征图;

卷积算子分组数同样为 g g g组,其维度(宽、高、通道数卷积核个数)为 K w × K h × C i g × C o g K_{w} \times K_{h} \times \frac{C_{i}}{g} \times \frac{C_{o}}{g} Kw×Kh×gCi×gCo

每一组中输入特征图和分组卷积核做卷积得到每一组的输出特征图维度为 W o × H o × C o g W_{o} \times H_{o} \times \frac{C_{o}}{g} Wo×Ho×gCo,g个组的输出特征图拼接在一起就是 W o × H o × C o W_{o} \times H_{o} \times C_{o} Wo×Ho×Co

理解其过程后,下面我们分析深度可分离卷积算子的参数量和计算量

(1) Params

对于单个分组卷积算子来说,其维度(宽、高、通道数)为 K w × K h × C i g K_{w} \times K_{h} \times \frac{C_{i}}{g} Kw×Kh×gCi偏置参数共有1个,单个分组的卷积核个数为 C o g \frac{C_{o}}{g} gCo,共有 g g g个分组卷积,故其参数量为:

P a r a m s = ( K w × K h × C i g + 1 ) × C o g × g Params=(K_{w} \times K_{h} \times \frac{C_{i}}{g}+1) \times \frac{C_{o}}{g}\times g Params=(Kw×Kh×gCi+1)×gCo×g

(1) FLOPs

对于分组卷积算子来说,同样的单个分组的卷积核在特征图上每滑动一次,将对应元素相乘后累加得到输出特征图中的一个像素点,因此,输出特征图中的一个像素点的计算量为:

( K w × K h × C i g ) + ( K w × K h × C i g − 1 ) + 1 (K_{w} \times K_{h} \times \frac{C_{i}}{g})+(K_{w} \times K_{h} \times \frac{C_{i}}{g}-1)+1 (Kw×Kh×gCi)+(Kw×Kh×gCi1+1

其中 K w × K h × C i g K_{w} \times K_{h} \times \frac{C_{i}}{g} Kw×Kh×gCi是做乘法运算的次数, K w × K h × C i g − 1 K_{w} \times K_{h} \times \frac{C_{i}}{g}-1 Kw×Kh×gCi1是做加法运算的次数, + 1 +1 +1是加偏置运算的加法次数(每次滑动需要一次加偏置操作,或者理解为每一个输出特征像素需要一次加偏置操作)。

单个分组的卷积输出特征图维度为 W o × H o × C o g W_{o} \times H_{o} \times \frac{C_{o}}{g} Wo×Ho×gCo,故对于单个分组卷积算子总的计算量为:

F L O P s 单个分组 = [ ( K w × K h × C i g ) + ( K w × K h × C i g − 1 ) + 1 ] × W o × H o × C o g FLOPs_{单个分组}=[(K_{w} \times K_{h} \times \frac{C_{i}}{g})+(K_{w} \times K_{h} \times \frac{C_{i}}{g}-1)+1]\times W_{o} \times H_{o} \times \frac{C_{o}}{g} FLOPs单个分组=[(Kw×Kh×gCi)+(Kw×Kh×gCi1+1]×Wo×Ho×gCo

又因为共有 g g g组操作,故其总的计算量为

F L O P s = [ ( K w × K h × C i g ) + ( K w × K h × C i g − 1 ) + 1 ] × W o × H o × C o g × g = 2 × K w × K h × C i g × W o × H o × C o FLOPs=[(K_{w} \times K_{h} \times \frac{C_{i}}{g})+(K_{w} \times K_{h} \times \frac{C_{i}}{g}-1)+1] \times W_{o} \times H_{o} \times \frac{C_{o}}{g}\times g\\ = 2\times K_{w} \times K_{h} \times \frac{C_{i}}{g} \times W_{o} \times H_{o} \times C_{o} FLOPs=[(Kw×Kh×gCi)+(Kw×Kh×gCi1+1]×Wo×Ho×gCo×g=2×Kw×Kh×gCi×Wo×Ho×Co

回顾一下普通卷积的参数量核计算量,可以发现分组卷积的参数量和计算量都是普通卷积的 1 g \frac{1}{g} g1倍。

4. ptflops

ptflops 是一个自动计算模型参数量和计算量的库,可以通过pip/conda直接下载,即

pip install ptflops

速度过慢时可以使用-i参数指定源,即

pip install ptflops -i https://pypi.tuna.tsinghua.edu.cn/simple

使用举例:

import torch
from torchvision.models import resnet18
from ptflops import get_model_complexity_info
  
model = resnet50()
macs, params = get_model_complexity_info(model, (3, 224, 224), as_strings=True,print_per_layer_stat=True, verbose=True)
                                           
print("MACs=", str(macs / 1e9) + '{}'.format("G"))
print("MACs=", str(macs / 1e6) + '{}'.format("M"))

虽然它可以自己计算模型的参数量和计算量,但是对一些自定义的层或算子不支持,并且不支持带有批量的计算。

参考:
全连接-普通卷积-深度可分离卷积-分组卷积-计算量和参数量
普通卷积、分组卷积和深度分离卷积概念以及参数量计算

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

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

相关文章

【Cookie 和 session 的区别】

会话(Session) 跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。cookie和session都是用来跟踪浏览器用户身份的会话方式。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。 我们目前使用…

游戏AI:游戏开发和运营的新增长点

游戏AI(Game AI)是指在游戏开发运营的过程中模拟人类玩家或创建虚构性对手行为的人工智能技术。游戏AI的目标是增强游戏的互动性、可玩性和挑战性,使游戏中的角色能够智能地做出决策和行为。在游戏的开发和运营过程中使用人工智能技术&#x…

热敏电阻B值含义

1.B值(材料常数) 也称为β值,该热敏电阻规格是NTC热敏电阻的电阻与温度之间关系的特定曲线。它是一个描述热敏电阻材料物理特性的参数,也是热灵敏度指标,B值越大,表示热敏电阻器的灵敏度越高。应注意的是&a…

如何利用反欺诈(羊毛盾)API提升电商平台交易安全性?

前言 近年来,随着网络交易的普及和互联网金融的快速发展,各类网络欺诈事件层出不穷。面对这些问题,电商平台必须采取有效的措施来保障交易安全。而反欺诈(羊毛盾)API正是一种高效、智能的解决方案,能够帮助…

postswigger 靶场(CSRF)攻略-- 2.令牌验证

靶场地址: What is CSRF (Cross-site request forgery)? Tutorial & Examples | Web Security Academy (portswigger.net)https://portswigger.net/web-security/csrf 令牌(token)验证取决于请求方法 题目中已告知易受攻击的是电子邮件的更改功能&#xff0…

web自动化框架之四测试报告的搭建

现状: 看过前面的文章,楼主用的是python,所以在搭建测试报告这块的时候使用的是unittesthtmlTestRunner;然后发现生成出来的报告,总是有那么不完美的地方,比如想增加图片,比如显示风格改变下&a…

DBever连接PG库

一、简介 DBeaver是一种通用数据库管理工具,适用于需要以专业方式使用数据的每个人;适用于开发人员,数据库管理员,分析师和所有需要使用数据库的人员的 免费(DBeaver Community) 的多平台数据库工具,支持 Windows、Li…

【哈夫曼树的构造和查找最小的的权值结点代码,哈夫曼编码的算法实现】

文章目录 哈夫曼树的构造和查找最小的的权值结点代码哈夫曼编码思想哈夫曼编码的算法实现 哈夫曼树的构造和查找最小的的权值结点代码 #include<iostream> using namespace std;typedef struct {int parent, lch, rch;//双亲结点和孩子结点的下标int weight;//权值 }htN…

ChinaSoft 论坛巡礼|开源软件供应链论坛

2023年CCF中国软件大会&#xff08;CCF ChinaSoft 2023&#xff09;由CCF主办&#xff0c;CCF系统软件专委会、形式化方法专委会、软件工程专委会以及复旦大学联合承办&#xff0c;将于2023年12月1-3日在上海国际会议中心举行。 本次大会主题是“智能化软件创新推动数字经济与社…

Go语言安装教程

【Go系列-1】-Go安装教程 环境提前准备 安装的时候可以选择自己的目录进行环境管理 E:\Z_Enviroment\Go创建文件夹&#xff1a; E:\Z_Enviroment\Go E:\Z_Enviroment\GoWorks E:\Z_Enviroment\GoWorks\bin E:\Z_Enviroment\GoWorks\pkg E:\Z_Enviroment\GoWorks\src环境变量…

OpenCV:图像噪点消除与滤波算法

人工智能的学习之路非常漫长&#xff0c;不少人因为学习路线不对或者学习内容不够专业而举步难行。不过别担心&#xff0c;我为大家整理了一份600多G的学习资源&#xff0c;基本上涵盖了人工智能学习的所有内容。点击下方链接,0元进群领取学习资源,让你的学习之路更加顺畅!记得…

测试架构师基础-进阶体系知识点、性能测试安全测试

一、Linux必备知识 linux作为现在最流行的软件环境系统&#xff0c;一定需要掌握&#xff0c;目前的招聘要求都需要有linux能力。 二、Shell脚本 掌握shell脚本&#xff0c;包括shell基础与应用、shell逻辑控制、shell逻辑函数等。 三、互联网程序原理 自动化必由之路&#…

pid调参(实验室新人入门)

安装keil&#xff1a;下载MDK-ARM http://t.csdnimg.cn/yYF7W芯片包&#xff1a; https://www.keil.arm.com/devices/stmicroelectronics-stm32f429aghx/features/ 调参软件&#xff1a; https://blog.csdn.net/weixin_63568691/article/details/133606043调参方法&#xff1a;…

CSRF 漏洞详解

CSRF 漏洞详解 文章目录 CSRF 漏洞详解漏洞描述漏洞原理漏洞场景漏洞评级漏洞危害漏洞验证漏洞利用漏洞防御典型案例 漏洞描述 CSRF&#xff08;Cross-Site Request Forgery&#xff09;漏洞是一种Web应用程序安全漏洞&#xff0c;它允许攻击者利用受害者的已认证会话来执行未…

纯c语言模拟栈和队列(初学必看)

一、栈(Stack) 1.栈的概念及其结构 栈是一种特殊的线性表&#xff0c;在栈这个结构里&#xff0c;越先存进去的数据越难取出来。 这个结构就像是一个只有一端有打开的容器&#xff0c;越先放进去的球越在底部&#xff0c;想要把底部的球拿出来&#xff0c;就必须先把前面的求…

Python实现WOA智能鲸鱼优化算法优化卷积神经网络分类模型(CNN分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 鲸鱼优化算法 (whale optimization algorithm,WOA)是 2016 年由澳大利亚格里菲斯大学的Mirjalili 等提…

快速验证微信小程序的AppId和AppSecret是否正确

解决方案说明 该验证方法是一种敏捷且高效的方式&#xff0c;特别适用于快速确认给定的 AppID 和 AppSecret 是否有效。在处理大量凭证或需要频繁验证的情况下&#xff0c;这种方法可以帮助您迅速而准确地完成验证过程。 特点 快速验证&#xff1a; 通过调用微信开放平台的接…

Selenium浏览器自动化测试框架简单介绍

selenium简介 介绍 Selenium [1] 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中&#xff0c;就像真正的用户在操作一样。支持的浏览器包括IE&#xff08;7, 8, 9, 10, 11&#xff09;&#xff0c;Mozilla Firefox&#xff0c;Safari&#xff0c;Google …

Rust编程中的线程间通信

1.消息传递 为了实现消息传递并发&#xff0c;Rust 标准库提供了一个 信道&#xff08;channel&#xff09;实现。信道是一个通用编程概念&#xff0c;表示数据从一个线程发送到另一个线程。 可以将编程中的信道想象为一个水流的渠道&#xff0c;比如河流或小溪。如果你将诸如…