张量与数据类型
Pytorch最基本的操作对象——张量(tensor),张量是Pytorch中重要的数据结构,可认为是一个高维数组。一般的,标量(scalar)是只有大小没有方向的量,如1、2、3等;向量(vector)是有大小和方向的量,如[1,2,3];矩阵(matrix)是由多个向量组成的,如[[1,2,3],[4,5,6]]。张量是基于向量和矩阵的推广,可以将标量视为零阶张量,向量可以视为一阶张量,矩阵是二阶张量。张量是支持高效的科学计算的数组,它可以是一个数(标量)、一维数组(向量)、二维数组(矩阵)和更高维的数组(高阶数据)。
1.1 PyTorch张量
PyTorch最基本的操作对象是张量,表示一个多维数组,张量类似NumPy的数组(ndarray),与ndarray不同的是,张量可以在GPU使用以加速计算。张量和NumPy的数组通常可以共享相同的低层内存,无须复制数据。
演示张量的创建和运算,首先导入PyTorch和NumPy,代码如下:
import torch
import numpy as np
1.1.1 初始化张量
可以使用多种形式初始化张量,如可直接从Python数据创建张量,无须指定类型,PyTorch会自动推荐其类型,可通过张量的dtype属性查看其类型。
t = torch.tensor([1, 2]) #创建一个张量
print(t) #输出 tensor([1, 2])
print(t.dtype) #输出 torch.int64
代码输出:
tensor([1, 2])
torch.int64
在创建张量时,如果想直接创建为float类型,可使用torch.FloatTensor()方法;如果需要明确的创建为Int类型,可使用torch.LongTensor()方法。这两种类型是PyTorch中使用最多、最常见的两种类型。代码如下:
t = torch.FloatTensor([1, 2])
print(t)
print(t.dtype)
代码输出:
tensor([1., 2.])
torch.float32
======================= 代码分割线 =========================
t = torch.LongTensor([1, 2])
print(t)
print(t.dtype)
代码输出:
tensor([1, 2])
torch.int64
也可以使用torch.from_numpy()方法从NumPy数组ndarray张量。
np_array=np.array([[1,2],[3,4]]) #创建一个ndarray
t_np=torch.from_numpy(np_array) #从ndarray创建张量
t_np
代码输出:
tensor([[1, 2],[3, 4]], dtype=torch.int32)
1.1.2 张量类型
PyTorch 张量的基础数据类型主要包含以下几种:
torch.float32
(或torch.float
):32 位浮动点数,最常用的数据类型,用于表示小数。torch.float64
(或torch.double
):64 位浮动点数,用于需要更高精度的计算。torch.float16
(或torch.half
):16 位浮动点数,常用于减少内存消耗和加速计算,尤其是在GPU上。torch.int8
:8 位整数,用于表示整数值。torch.int16
:16 位整数。torch.int32
:32 位整数,常用整数类型。torch.int64
(或torch.long
):64 位整数,通常用于较大的整数或索引。torch.uint8
:8 位无符号整数,通常用于处理图像数据(如像素值)。torch.bool
:布尔类型,值为True
或False
,用于逻辑运算。
不同数据类型适用于不同的任务和计算需求。在实际使用时,可以根据需求选择合适的张量数据类型,尤其是在性能和内存管理方面。
其中32位浮点型和64位整型是最常用的类型,这两种类型也常常被表示为torch.float和torch.long,也就是说,torch.float32等价于torch.float,torch.int64等价于torch.long,这两种类型正好对应上面的两种创建张量的方法torch.LongTensor()和torch.FloatTensor()。可在构造张量时使用dtype明确其类型。
t = torch.tensor([1,2], dtype=torch.float32)
print(t)
print(t.dtype)
代码输出:
tensor([1., 2.])
torch.float32
======================= 代码分割线 =========================
#也可以使用torch.float作为dtype的参数
t = torch.tensor([1,2], dtype=torch.float)
print(t)
print(t.dtype)
代码输出:
tensor([1., 2.])
torch.float32
======================= 代码分割线 =========================
print(torch.float==torch.float32) #返回True
print(torch.long==torch.int64) #返回True
代码输出:
True
True
以上代码中直接将torch.float与torch.float32做相等判断,判断后发现返回结果为True,说明这两个写法是完全等价的。PyTorch针对torch.float32与torch.int64类型有专门这样的简写形式是因为,这两种类型特别重要,模型的输入类型一般都是torch.float32,而模型分类问题的标签类型一般为torch.int64。
PyTorch中张量的类型可以使用type()方法转换,代码如下。
t = torch.tensor([1,2], dtype=torch.float32)
print(t.dtype)
#type()方法转换类型
t=t.type(torch.int64)
print(t.dtype)
代码输出:
torch.float32
torch.int64
编写代码过程中,由于转换为torch.float32和torh.int64两个类型最常见,框架提供了两个快捷的实例转换方法,即float()方法和long()方法。代码如下。
t = torch.tensor([1,2], dtype=torch.float32)
t=t.long()
print(t.dtype)
t=t.float()
print(t.dtype)
代码输出 :
torch.int64
torch.float32
1.1.3 创建随机值张量
可使用torch.rand()方法创建0~1均匀的随机数,使用torch.randn()方法创建标准正态分布随机数,使用torch.zeros()和torch.ones()方法创建全0和全1的张量,代码如下。
t = torch.rand(2, 3)
print(t)
代码输出:
tensor([[0.7330, 0.2682, 0.0917],[0.8569, 0.2710, 0.8089]])
======================= 代码分割线 =========================
t = torch.rand(2, 3)
print(t)
代码输出:
tensor([[0.5205, 0.9647, 0.5108],[0.7746, 0.4297, 0.5655]])
======================= 代码分割线 =========================
t = torch.zeros(3)
print(t)
代码输出:
tensor([0., 0., 0.])
======================= 代码分割线 =========================
t = torch.ones(3, 2)
print(t)
代码输出:
tensor([[1., 1.],[1., 1.],[1., 1.]])
还可以从另一个张量创建新的张量,除非明确覆盖,否则新的张量保留原来张量的属性(形状、数据类型),如下所示。
x = torch.zeros_like(t) #类似的方法还有torch.ones_like()
print(x)
代码输出:
tensor([[0., 0.],[0., 0.],[0., 0.]])
======================= 代码分割线 =========================
x = torch.rand_like(t)
print(x)
代码输出:
tensor([[0.2793, 0.3023],[0.5073, 0.3336],[0.7823, 0.4880]])
1.1.4 张量属性
tensor.shape属性可返回张量的形状,它与tensor.size()方法等价,后者更灵活,可以通过给定参数返回某一个维度的形状;tensor.dtype属性可返回当前张量的类型。代码如下。
t=torch.ones(2,3,dtype=torch.float64)
print(t.shape) #输出torch.Size([2, 3])
print(t.size()) #输出torch.Size([2, 3])
print(t.size(1)) #输出第一维度大小 3
print(t.dtype) #输出torch.float64
print(t.device) #输出cpu
代码输出:
torch.Size([2, 3])
torch.Size([2, 3])
3
torch.float64
cpu
可通过使用tensor.device属性查看当前张量所在的设备(device)。直接创建的张量都在内存中,所以显示的device是CPU,如果是显存中的张量,则显示为CUDA。
1.1.5 将张量移动到显存
张量可进行算术运算、线性代数、矩阵操作等计算,这些计算可以在CPU上运行,也可在GPU运行,在GPU上的运算速度通常高于CPU。默认情况下是在CPU创建张量。如果有可用的GPU,可以使用tensor.to()方法明确地将张量移动到GPU。代码如下。
#如果GPU可用,将张量移动到显存
if torch.cuda.is_available():t = t.to('cuda')
print(t.device) #如果GPU可用,输出类似device(type='cuda',index=0)
代码输出:
cpu
在编码过程中,一般可用如下代码获取当前可用设备。
#获取当前可用设备
device="cuda" if torch.cuda.is_available() else "cpu"
print("Using {} device".format(device)) #打印当前可用设备
t=t.to(device) #将t放到当前可用设备上
print(t.device) #如果GPU可用,输出类似device(type='cuda',index=0)
代码输出:
Using cpu device
cpu
这样设置要比直接使用t.to(‘cuda’)更稳妥,可以确保代码中无论有无GPU都能正常运行,并且如果GPU可用就用GPU.
1.2 张量运算
张量的运算规则、切片索引规则与NumPy类似,运算中遵循广播原则和同形状相同位置元素对方运算的原则,代码如下。
t1 = torch.randn(2, 3)
t2 = torch.ones(2, 3)
print(t1 + 3) #t1中每一个元素都加3
print(t1 + t2) #t1与t2中每一个相同位置的元素相加
print(t1.add(t2)) #等价于t1+t2,结果与上面相同print(t1) #输出当前t1值
t1.add_(t2) #运行add_这个计算方法,add_方法中的下划线代表就地改变原值
print(t1) #查看运行结果
代码输出:
tensor([[2.8404, 2.7435, 4.1129],[2.7789, 4.4589, 4.5274]])
tensor([[0.8404, 0.7435, 2.1129],[0.7789, 2.4589, 2.5274]])
tensor([[0.8404, 0.7435, 2.1129],[0.7789, 2.4589, 2.5274]])
tensor([[-0.1596, -0.2565, 1.1129],[-0.2211, 1.4589, 1.5274]])
tensor([[0.8404, 0.7435, 2.1129],[0.7789, 2.4589, 2.5274]])
在PyTorch中,如果一个运算方法后面加上下画线,代表就地改变原值,即t1.add_(t2)会直接将运算结果保存为t1,这样做可以节省内存,但是缺点是会直接改变t1原值,因为在使用的时候需要谨慎。
张量可以进行常见的算术运算,如abs(绝对值)、cunsum(累加)、divide(除)、floor_divide(整除)、mean(均值)、min(最小值)、max(最大值)、multiply(乘)等,这里不再一一演示。在深度学习中,矩阵运算常用到转置(tensor.T)和矩阵乘法(matmul或@),代码如下。
print(t1.matmul(t2.T)) #t1与t2的转置进行矩阵乘法
print(t1@(t2.T)) #与上一行运行等价,t1与t2的转置进行矩阵乘法
代码输出:
tensor([[3.6968, 3.6968],[5.7652, 5.7652]])
tensor([[3.6968, 3.6968],[5.7652, 5.7652]])
对于只有一个元素的张量,可以使用tensor.item()方法将其转换为标量,也就是Python的基本类型。
t3 = t1.sum()
print(t3) #t3是只有一个元素的张量
print(t3.item()) #输出一个Python浮点数
代码输出:
tensor(9.4620)
9.461990356445312
以上代码中,首先将张量中所有的元素求和,得到只有一个元素的张量,然后使用tensor.item()方法将其转为标量,这种转换在我们希望打印模型正确率和损失值的时候很常见。
1.2.1 与NumPy数据类型的转换
1.1.1节演示了可使用torch.from_numpy()方法将ndarray转为张量,张量也可以使用tensor.numpy()方法得到它对应的ndarray数组,它们共用相同的内存。
### 与ndarray数据类型的转换import numpy as np
a = np.random.randn(2, 3) #创建一个形状为(2,3)的ndarray
print(a) #输出此ndarray
t = torch.from_numpy(a) #使用此ndarray创建一个张量
print(t)
print(t.numpy()) #使用tensor.numpy()方法获得张量对应的ndarray
代码输出:
[[ 0.22605693 0.04398624 -0.21096077][-0.66368309 1.23512604 2.0399825 ]]
tensor([[ 0.2261, 0.0440, -0.2110],[-0.6637, 1.2351, 2.0400]], dtype=torch.float64)
[[ 0.22605693 0.04398624 -0.21096077][-0.66368309 1.23512604 2.0399825 ]]
1.2.2 张量的变形
tensor.size()方法和tensor.shape属性可以返回张量的形状。当需要改变张量的形状时,可以通过tensor.view()方法,这个方法相当于NunPy中的reshape方法,用于改变张量的形状。需要注意的是,在转换过程要确保元素数量一致。代码如下。
t=torch.randn(4,6) #创建一个形状为(4,6)的张量
print(t.shape) #输出t的形状为torch.Size([4, 6])
t1=t.view(3,8) #调整成(3,8)形状,这里元素数量是相等的
print(t1.shape) #输出t1的形状为torch.Size([3, 8])
代码输出:
torch.Size([4, 6])
torch.Size([3, 8])
======================= 代码分割线 =========================
#现在我们需要将t展平为最后一个维度为1的张量
#第二个参数1代表第二维长度为1,参数-1表示根据元素个数自动计算第一维
t1=t.view(-1,1)
print(t1.shape)
代码输出:
torch.Size([24, 1])
======================= 代码分割线 =========================
# 也可以使用view增加维度,当然元素个数是不变的
t1=t.view(1,4,6) #调整成三维的,其中第一维的长度为1
print(t1.shape)
代码输出:
torch.Size([1, 4, 6])
对于维度长度为1的张量,可以使用torch.squeeze()方法去掉长度为1的维度,相应的也有一 个增加长度为1维度的方法,即torch.unsqueeze(),代码如下。
t2=torch.squeeze(t1)
print(t2.shape)
代码输出:
torch.Size([4, 6])
======================= 代码分割线 =========================
t3=torch.unsqueeze(t2,0) #参数0表示指定在第一个维度上增加维度
print(t3.shape)
代码输出:
torch.Size([1, 4, 6])
1.3 张量的自动微分
在PyTorch中,张量有一个requires_grad属性,可以在创建张量时指定些属性为True。如果requires_grad属性被设置为True,PyTorch将开始跟踪对此张量的所有计算,完成计算后,可以对计算结果调用backward() 方法,PyTorch将自动计算所有梯度。该张量的梯度将累加到.grad属性中。张量的grad_fn属性则指向运算生成此张量的方法。简单的说,张量的requires_grad属性用来明确是否跟踪张量的梯度,grad属性表示计算得到的梯度,grad_fn属性表示运算得到生成此张量的方法。代码演示如下。注意查看代码中的注释。
t = torch.ones(2, 2, requires_grad=True) # 这里设置 requires_grad 为True
print(t.requires_grad) # 输出 True
print(t.grad) # tensor.grad输出张量的梯度,这里输出 None,因为目前 t 没有梯度
print(t.grad_fn) # tensor.grad_fn指向运算生成此张量的方法,这里为 None# 进行张量运算,得到 y
y = t + 5
print(y) # 输出 tensor([[6., 6.],[6., 6.]], grad_fn=<AddBackward0>)
# y由于是运算而创建的,因此grad_fn属性不是空
print(y.grad_fn) # 输出类似<AddBackward0 object at 0x00000237DF1A4250># 进行更多运算
z = y * 2
out = z.mean() #求张量的均值,实例方法
print(out) # 输出 tensor(12., grad_fn=<MeanBackward0>)
代码输出:
True
None
None
tensor([[6., 6.],[6., 6.]], grad_fn=<AddBackward0>)
<AddBackward0 object at 0x000001B460445750>
tensor(12., grad_fn=<MeanBackward0>)
上面的代码中,首先创建了张量,并指定requires_grad属性为True,因为这是一个新创建的张量,它的grad和grad_fn属性均为空。然后经过加法、乘法和取均值运算,得到了out这个最终结果。注意:现在out只有单个元素,它是一个标量值。下面在out上执行自动微分运算,并输出t的梯度(d(out)/d(x)微分运算的结果),代码如下。
out.backward() # 自动微分运算, 注意 out 是标量值
print(t.grad) #输出t的梯度,也就是d(out)/d(x)微分运算的结果
代码输出:
tensor([[0.5000, 0.5000],[0.5000, 0.5000]])
当张量的 requires_grad 属性为 True 时,PyTorch会一直跟踪记录此张量的运算;
print(t.requires_grad) # 输出 True ,PyTorch框架会跟踪此张量的运算
s = t + 2 # 进行运算,得到新的张量 s
print(s.requires_grad) # 输出 True ,PyTorch框架会继续跟踪此张量的运算
代码输出:
True
True
也可使用 tensor.detach() 来获得具有相同内容但不需要跟踪运算的新张量,可以认为获取张量的值,代码如下。
print(out.requires_grad) # 输出 True
s = out.detach() # 获取out的值,也可以使用out.data()方法
print(s.requires_grad) # 输出 False
代码输出:
True
False
可以使用 requires_grad_() 就地改变张量的这个属性,当我们希望模型的参数不再随着训练变化时,可以用此方法,代码如下:
print(t.requires_grad) # 输出 True
t.requires_grad_(False) # 就地改变requires_grad为False
print(t.requires_grad) # 输出 False
代码输出:
True
False
1.4 小结
讲解了张量的创建、PyTorch数据类型、张量运算、张量自动微分等基础知识,这是PyTorch中比较基础的内容。
相关文章:
张量与数据类型
Pytorch最基本的操作对象——张量(tensor),张量是Pytorch中重要的数据结构,可认为是一个高维数组。一般的,标量(scalar)是只有大小没有方向的量,如1、2、3等;向量&#x…...
torchvision.utils.make_grid 解释下
torchvision.utils.make_grid 是 PyTorch 中 torchvision 库提供的一个实用函数,用于将多个图像拼接成一个网格,方便进行可视化。 主要功能 make_grid 将一批图片组织成一个网格形式,输出一个单一的张量,便于使用可视化工具(如 Matplotlib)查看图像。 参数解释 torchvi…...
Android原生Widget使用步骤
需要创建三个XML文件以及一个Class文件 三个XML文件分别是 Widget布局文件 <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_p…...
实验八 指针2
7-1 利用指针返回多个函数值 分数 30 全屏浏览 切换布局 作者 陈晓梅 单位 广东外语外贸大学 读入n个整数,调用max_min()函数求这n个数中的最大值和最小值。 输入格式: 输入有两行: 第一行是n值; 第二行是n个数。 输出格式: 输出最大…...

1 数据库(下):多表设计 、多表查询 + SQL中的with查询语法(MySQL8.0以后版本才支持这种新语法)+ 数据库优化(索引优化)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、多表设计1 多表设计-概述2 三种多表关系一对多(多对一)(1)无外键约束(逻辑外键)&…...
什么是.net framework,什么是.net core,什么是.net5~8,版本对应关系
我不知道有多少人和我一样,没学习过.netCore,想要学习,但是版本号太多就蒙了,不知道学什么了,这里解释下各个版本的关系 我们一般开始学习微软的时候,都是开始学习的.netframework,常用的就是4…...

vulhub-wordpress靶场
一.主题上传漏洞 来到靶场点击主题选择add new 这里有一个上传主题的地方 我们可以去网上找到wordpress主题下载一个 wordpress模板 网页设计模板 免费 免费下载 - 爱给网 下载完成后对我们有用的东西只有这一个目录,把它拖出来 点开moban目录后,创建…...
安装与配置
《PHP Libxml》是一个在PHP中处理XML和HTML文档的重要库。它提供了丰富的API,支持DOM、SimpleXML和XMLReader等多种解析方式,广泛应用于各种编程语言和项目中。 安装与配置 安装: 在PHP中,libxml扩展通常是默认启用的。如果你需要手动安装&…...
斗鱼Android面试题及参考答案
常用的图片框架有哪些? Glide:是一个快速高效的 Android 图片加载库,专注于平滑滚动。它支持多种图片格式,包括 GIF,具有高效的缓存策略,能自动管理图片的生命周期,避免内存泄漏和 OOM 错误。其 API 简洁易用,可轻松实现图片的加载、显示和缓存等功能,如一行代码即可实…...

Could not install Gradle distribution from 的解决办法
在安装完成AndroidStudio之后,运行工程出现如下错误 Could not install Gradle distribution from https://services.gradle.org/distributions/gradle-6.5-bin.zip. 错误原因是:对应版本的Gradle文件下载失败了,我这里是gradle-6.5-bin.zip,不同版本的android studio也可…...
基于 SensitiveWordBs 实现敏感词过滤功能
在现代的互联网应用中,敏感词过滤已成为一个必不可少的功能,尤其是在社交媒体、评论审核等需要保证内容健康的场景下。本文将基于开源库https://github.com/houbb/sensitive-word,详细讲解如何通过自定义敏感词库和工具类实现高效的敏感词过滤…...

网络安全威胁2024年中报告
下载地址: 网络安全威胁2024年中报告-奇安信...

批次特征组杂记
批次特征组杂记 运维的时候新增了一个批次特征,然后发现不能按照要求跑到之前已经分好的批次特征组。 研究了半天原来是通过布局实现的。 特此记录。...

【HarmonyOS】解决自定义弹框和键盘之间安全距离的问题
【HarmonyOS】解决自定义弹框和键盘之间安全距离的问题 一、问题背景 我们在应用开发评论输入框时,常规的需求样式是:输入框view和键盘贴近,上半部展示信息区的形式,这样的设计,方便用户不割裂的去评论发言。 但是在…...

如何在LabVIEW中更好地使用ActiveX控件?
在LabVIEW中,ActiveX控件可以帮助实现与其他应用程序或第三方组件的集成(例如Microsoft Excel、Word、Internet Explorer等)。以下是一些建议,帮助您更好地在LabVIEW中使用ActiveX控件: 1. 理解ActiveX控件的基本原…...
【视觉SLAM:四、相机与图像】
相机模型 相机模型是计算机视觉中的重要内容,用于描述真实相机如何将三维世界投影到二维图像平面。以下从多个角度介绍常见的相机模型。 针孔相机模型 针孔相机模型是最简单的相机模型,用数学公式描述从三维世界到二维图像平面的映射关系。核心公式如…...

如何利用无线路由器实现水泵房远程监测管理
水泵站广泛部署应用在工农业用水、防洪、排涝和抗旱减灾等方面,如果水泵站发生异常,往往会对生产生活造成诸多损失,甚至引发安全事故。因此,建立一套高效、可靠的泵站远程监测管理系统至关重要。 方案背景 目前,我国大…...

使用ArcGIS Pro自带的Notebook计算多个遥感指数
在之前的分享中,我们介绍了如何使用ArcPy将GEE下载的遥感影像转为单波段文件。基于前面创建的单波段文件,我们可以一次性计算多种遥感指数,例如NDVI、EVI、NDSI等。我这里直接在ArcGIS Pro中自带的Notebook进行的运行。如下图所示,…...

宝塔-firefox(Docker应用)-构建自己的Web浏览器
安装基础软件 宝塔中安装firefox(Docker应用) 。宝塔中需要先安装docker及docker-composefirefox配置安装 点击firefox应用,选择【安装配置】点击右边绿色按钮,进行安装,这一步等待docker-compose根据你的配置初始化docker应用 等待安装 …...

OpenCV-Python实战(8)——图像变换
一、缩放 cv2.resize() img cv2.resize(src*,dsize*,fx*,fy*,interpolation*) img:目标图像。 src:原始图像。 dsize:(width,height)图像大小。 fx、fy:可选参数,水平/垂直方向…...

Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...