当前位置: 首页 > news >正文

pytorch多GPU训练教程

在这里插入图片描述

pytorch多GPU训练教程

文章目录

  • pytorch多GPU训练教程
    • 1. Torch 的两种并行化模型封装
      • 1.1 DataParallel
      • 1.2 DistributedDataParallel
    • 2. 多GPU训练的三种架构组织方式
      • 2.2 数据不拆分,模型拆分(Model Parallelism)
      • 2.3 数据拆分,模型拆分(Pipeline Parallelism)
    • 3. NCCL以及DistributedSampler
      • 3.1 NCCL
      • 3.2 常见参数
      • 3.3 DistributedSampler
      • 4.2 多卡训练多进程调试办法(Pycharm为例)
    • 附:参考链接

1. Torch 的两种并行化模型封装

1.1 DataParallel

DataParallel 是 PyTorch 提供的一种数据并行方法,用于在单台机器上的多个 GPU 上进行模型训练。它通过将输入数据划分成多个子部分(mini-batches),并将这些子部分分配给不同的 GPU,以实现并行计算。
在前向传播过程中,输入数据会被划分成多个副本并发送到不同的设备(device)上进行计算。模型(module)会被复制到每个设备上,这意味着输入的批次(batch)会被平均分配到每个设备,但模型会在每个设备上有一个副本。每个模型副本只需要处理对应的子部分。需要注意的是,批次大小应大于GPU数量。在反向传播过程中,每个副本的梯度会被累加到原始模型中。总结来说,DataParallel会自动将数据切分并加载到相应的GPU上,将模型复制到每个GPU上,进行正向传播以计算梯度并汇总。
注意:DataParallel是单进程多线程的,仅仅能工作在单机中。
封装示例:

import torch
import torch.nn as nn
import torch.optim as optim# 定义模型
class SimpleModel(nn.Module):def __init__(self):super(SimpleModel, self).__init__()self.fc = nn.Linear(10, 1)def forward(self, x):return self.fc(x)# 初始化模型
model = SimpleModel()# 使用 DataParallel 将模型分布到多个 GPU 上
model = nn.DataParallel(model)

1.2 DistributedDataParallel

DistributedDataParallel (DDP) 是 PyTorch 提供的一个用于分布式数据并行训练的模块,适用于单机多卡和多机多卡的场景。相比于 DataParallel,DDP 更加高效和灵活,能够在多个 GPU 和多个节点上进行并行训练。
DistributedDataParallel是多进程的,可以工作在单机或多机器中。DataParallel通常会慢于DistributedDataParallel。所以目前主流的方法是DistributedDataParallel。
封装示例:

import torch
import torch.nn as nn
import torch.optim as optim
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDPdef main(rank, world_size):# 初始化进程组dist.init_process_group("nccl", rank=rank, world_size=world_size)# 创建模型并移动到GPUmodel = SimpleModel().to(rank)# 包装模型为DDP模型ddp_model = DDP(model, device_ids=[rank])if __name__ == "__main__":import osimport torch.multiprocessing as mp# 世界大小:总共的进程数world_size = 4# 使用mp.spawn启动多个进程mp.spawn(main, args=(world_size,), nprocs=world_size, join=True)

2. 多GPU训练的三种架构组织方式


由于上一节的讨论,本节所有源码均由DDP封装实现。
###2.1 数据拆分,模型不拆分(Data Parallelism)
数据并行(Data Parallelism)将输入数据拆分成多个子部分(mini-batches),并分配给不同的 GPU 进行计算。每个 GPU 上都有一份完整的模型副本。这种方式适用于模型相对较小,但需要处理大量数据的场景。
由于下面的代码涉及了rank、world_size等概念,这里先做一下简要普及。
** Rank**
rank 是一个整数,用于标识当前进程在整个分布式训练中的身份。每个进程都有一个唯一的 rank。rank 的范围是 0 到 world_size - 1。

  • 用于区分不同的进程。
  • 可以根据 rank 来分配不同的数据和模型部分。

World Size
world_size 是一个整数,表示参与分布式训练的所有进程的总数。

  • 确定分布式训练中所有进程的数量。
  • 用于初始化通信组,确保所有进程能够正确地进行通信和同步。

Backend
backend 指定了用于进程间通信的后端库。常用的后端有 nccl(适用于 GPU)、gloo(适用于 CPU 和 GPU)和 mpi(适用于多种设备)。

  • 决定了进程间通信的具体实现方式。
  • 影响训练的效率和性能。

Init Method
init_method 指定了初始化分布式环境的方法。常用的初始化方法有 TCP、共享文件系统和环境变量。

  • 用于设置进程间通信的初始化方式,确保所有进程能够正确加入到分布式训练中。

Local Rank
local_rank 是每个进程在其所在节点(机器)上的本地标识。不同节点上的进程可能会有相同的 local_rank。

  • 用于将每个进程绑定到特定的 GPU 或 CPU。
import torch
import torch.nn as nn
import torch.optim as optim
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
import torch.multiprocessing as mpclass SimpleModel(nn.Module):def __init__(self):super(SimpleModel, self).__init__()self.fc = nn.Linear(10, 1)def forward(self, x):return self.fc(x)def train(rank, world_size):dist.init_process_group(backend='nccl', init_method='tcp://127.0.0.1:29500', rank=rank, world_size=world_size)model = SimpleModel().to(rank)ddp_model = DDP(model, device_ids=[rank])criterion = nn.MSELoss().to(rank)optimizer = optim.SGD(ddp_model.parameters(), lr=0.01)inputs = torch.randn(64, 10).to(rank)targets = torch.randn(64, 1).to(rank)outputs = ddp_model(inputs)loss = criterion(outputs, targets)optimizer.zero_grad()loss.backward()optimizer.step()dist.destroy_process_group()if __name__ == "__main__":world_size = 4mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)

2.2 数据不拆分,模型拆分(Model Parallelism)

模型并行(Model Parallelism)将模型拆分成多个部分,并分配给不同的 GPU。输入数据不拆分,但需要通过不同的 GPU 处理模型的不同部分。这种方式适用于模型非常大,单个 GPU 无法容纳完整模型的场景。

import torch
import torch.nn as nn
import torch.optim as optim
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
import torch.multiprocessing as mpclass ModelParallelModel(nn.Module):def __init__(self):super(ModelParallelModel, self).__init__()self.fc1 = nn.Linear(10, 10).to('cuda:0')self.fc2 = nn.Linear(10, 1).to('cuda:1')def forward(self, x):x = x.to('cuda:0')x = self.fc1(x)x = x.to('cuda:1')x = self.fc2(x)return xdef train(rank, world_size):dist.init_process_group(backend='nccl', init_method='tcp://127.0.0.1:29500', rank=rank, world_size=world_size)model = ModelParallelModel()ddp_model = DDP(model, device_ids=[rank])criterion = nn.MSELoss().to('cuda:1')optimizer = optim.SGD(ddp_model.parameters(), lr=0.01)inputs = torch.randn(64, 10).to('cuda:0')targets = torch.randn(64, 1).to('cuda:1')outputs = ddp_model(inputs)loss = criterion(outputs, targets)optimizer.zero_grad()loss.backward()optimizer.step()dist.destroy_process_group()if __name__ == "__main__":world_size = 2mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)

2.3 数据拆分,模型拆分(Pipeline Parallelism)

流水线并行(Pipeline Parallelism)结合了数据并行和模型并行。输入数据和模型都被拆分成多个部分,每个 GPU 处理部分数据和部分模型。这种方式适用于需要平衡计算和内存需求的大规模深度学习任务。

import torch
import torch.nn as nn
import torch.optim as optim
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
import torch.multiprocessing as mpclass PipelineParallelModel(nn.Module):def __init__(self):super(PipelineParallelModel, self).__init__()self.fc1 = nn.Linear(10, 10)self.fc2 = nn.Linear(10, 1)def forward(self, x):if self.fc1.weight.device != x.device:x = x.to(self.fc1.weight.device)x = self.fc1(x)if self.fc2.weight.device != x.device:x = x.to(self.fc2.weight.device)x = self.fc2(x)return xdef train(rank, world_size):dist.init_process_group(backend='nccl', init_method='tcp://127.0.0.1:29500', rank=rank, world_size=world_size)model = PipelineParallelModel()model.fc1.to('cuda:0')model.fc2.to('cuda:1')ddp_model = DDP(model)criterion = nn.MSELoss().to('cuda:1')optimizer = optim.SGD(ddp_model.parameters(), lr=0.01)inputs = torch.randn(64, 10).to('cuda:0')targets = torch.randn(64, 1).to('cuda:1')outputs = ddp_model(inputs)loss = criterion(outputs, targets)optimizer.zero_grad()loss.backward()optimizer.step()dist.destroy_process_group()if __name__ == "__main__":world_size = 2mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)

3. NCCL以及DistributedSampler

3.1 NCCL

NCCL是一个Nvidia专门为多GPU之间提供集合通讯的通讯库,或者说是一个多GPU卡通讯的框架 ,它具有一定程度拓扑感知的能力,提供了包括AllReduce、Broadcast、Reduce、AllGather、ReduceScatter等集合通讯API,也支持用户去使用ncclSend()、ncclRecv()来实现各种复杂的点对点通讯,如One-to-all、All-to-one、All-to-all等,在绝大多数情况下都可以通过服务器内的PCIe、NVLink、NVSwitch等和服务器间的RoCEv2、IB、TCP网络实现高带宽和低延迟。它解决了前文提到的GPU间拓补识别、GPU间集合通信优化的问题。NCCL屏蔽了底层复杂的细节,向上提供API供训练框架调用,向下连接机内机间的GPU以完成模型参数的高效传输。

3.2 常见参数

修改环境变量或在nccl.conf中修改相关参数选项。可以改变通信特点,进而起到影响通行性能的作用。
NCCL_P2P_DISABLE 默认是开启P2P通信的,这样一般会更高效,用到点对点通信延迟会有所改善,带宽也是。
NCCL_P2P_LEVEL 开启P2P后可以设置P2P的级别,比如在那些特定条件下可以开启点对点通信,具体的可以参看文档(0-5)
NCCL_SOCKET_NTHREADS 增加它的数量可以提高socker传输的效率,但是会增加CPU的负担
NCCL_BUFFLE_SIZE 缓存数据量,缓存越大一次ring传输的数据就越大自然对带宽的压力最大,但是相应的总延迟次数会少。缺省值是4M(4194304),注意设置的时候使用bytes(字节大小)
NCCL_MAX/MIN_NCHANNELS 最小和最大的rings,rings越多对GPU的显存、带宽的压力都越大,也会影响计算性能
NCCL_CHECKS_DISABLE 在每次集合通信进行前对参数检验校对,这会增加延迟时间,在生产环境中可以设为1.缺省是0
NCCL_CHECK_POINTERS 在每次集合通信进行前对CUDA内存 指针进行校验,这会增加延迟时间,在生产环境中可以设为1.缺省是0
NCCL_NET_GDR_LEVEL GDR触发的条件,默认是当GPU和NIC挂载一个swith上面时使用GDR
NCCL_IGNORE_CPU_AFFINITY 忽略CPU与应用的亲和性使用GPU与nic的亲和性为主
NCCL_ALGO 通信使用的算法,ring Tree Collnet
NCCL_IB_HCA 代表IB使用的设备:Mellanox mlx5系列的HCA设备
A40(GPU3-A40:596:596 [2] NCCL INFO NET/IB : Using [0]mlx5_0:1/IB ; OOB ib0:66.66.66.211<0>),
V100(gpu196-v100:786:786 [5] NCCL INFO NET/IB : Using [0]mlx5_0:1/IB [1]mlx5_1:1/IB ; OOB ib0:66.66.66.110<0>),
A100(GPU6-A100:686:686 [1] NCCL INFO NET/IB : Using [0]mlx5_0:1/RoCE [1]mlx5_2:1/IB [2]mlx5_3:1/IB ; OOB ib0:66.66.66.128<0>),
NCCL_IB_HCA=mlx5 会默认轮询所有的设备。
NCCL_IB_HCA=mlx5_0:1 指定其中一台设备。
a100有两个口,如果都开的话,会出现训练的浮动;如果指定只使用一个口,训练速度会下降。

3.3 DistributedSampler

DistributedSampler原理如图所示:假设当前数据集有0~10共11个样本,使用2块GPU计算。首先打乱数据顺序,然后用 11/2 =6(向上取整),然后6乘以GPU个数2 = 12,因为只有11个数据,所以再把第一个数据(索引为6的数据)补到末尾,现在就有12个数据可以均匀分到每块GPU。然后分配数据:间隔将数据分配到不同的GPU中。

BatchSampler原理: DistributedSmpler将数据分配到两个GPU上,以第一个GPU为例,分到的数据是6,9,10,1,8,7,假设batch_size=2,就按顺序把数据两两一组,在训练时,每次获取一个batch的数据,就从组织好的一个个batch中取到。注意:只对训练集处理,验证集不使用BatchSampler。

train_dset = NBADataset(obs_len=self.cfg.past_frames,pred_len=self.cfg.future_frames,training=True)self.train_sampler = torch.utils.data.distributed.DistributedSampler(train_dset)
self.train_loader = DataLoader(train_dset, batch_size=self.cfg.train_batch_size, sampler=self.train_sampler,num_workers=4, collate_fn=seq_collate)

##4. 多进程启动综合测试
###4.1 多卡训练多进程启动的两种方式
多卡训练启动有两种方式,其一是pytorch自带的torchrun,其二是自行设计多进程程序。

以下为torch,distributed.launch的简单demo:
运行方式为

# 直接运行
torchrun --nproc_per_node=4 test.py
# 等价方式
python -m torch.distributed.launch --nproc_per_node=4 test.py

torchrun实际上运行的是/usr/local/mambaforge/envs/led/lib/python3.7/site-packages/torch/distributed/launch.py(根据读者的环境变化)
python -m torch.distributed.launch也会找到这个程序的python文件执行,这个命令会帮助设置一些环境变量启动backend,否则需要自行设置环境变量。

import torch
import torch.distributed as dist
import torch.multiprocessing as mp
import torch.nn as nn
import torch.optim as optim
from torch.nn.parallel import DistributedDataParallel as DDP
import osdef example(rank, world_size):# create default process groupdist.init_process_group("nccl", rank=rank, world_size=world_size)# create local modelmodel = nn.Linear(10, 10).to(rank)# construct DDP modelddp_model = DDP(model, device_ids=[rank])# define loss function and optimizerloss_fn = nn.MSELoss()optimizer = optim.SGD(ddp_model.parameters(), lr=0.001)# forward passoutputs = ddp_model(torch.randn(20, 10).to(rank))labels = torch.randn(20, 10).to(rank)# backward passloss_fn(outputs, labels).backward()# update parametersoptimizer.step()def main():world_size = 2mp.spawn(example,args=(world_size,),nprocs=world_size,join=True)if __name__=="__main__":# Environment variables which need to be# set when using c10d's default "env"# initialization mode.os.environ["MASTER_ADDR"] = "localhost"os.environ["MASTER_PORT"] = "10086"main()
以下为multiprocessing的设计demo
import torch
import torch.distributed as dist
import torch.multiprocessing as mp
from torch.nn.parallel import DistributedDataParallel as DDPdef setup(rank, world_size):dist.init_process_group(backend='nccl',init_method='tcp://localhost:12355',rank=rank,world_size=world_size)torch.cuda.set_device(rank)dist.barrier()def cleanup():dist.destroy_process_group()def demo_basic(rank, world_size):setup(rank, world_size)model = torch.nn.Linear(10, 10).to(rank)ddp_model = DDP(model, device_ids=[rank])inputs = torch.randn(20, 10).to(rank)outputs = ddp_model(inputs)print(f"Rank {rank} outputs: {outputs}")cleanup()def main():world_size = torch.cuda.device_count()mp.spawn(demo_basic, args=(world_size,), nprocs=world_size, join=True)if __name__ == "__main__":main()

4.2 多卡训练多进程调试办法(Pycharm为例)

首先如果读者使用的是multiprocessing的方式,那么直接使用本地工具运行和调试即可,如果使用torchrun的方式,那么我们需要手动配置Run/Debug Configurations,根据4.1,我们要找到原型文件launch.py,以笔者的环境为例,我的launch文件在/usr/local/mambaforge/envs/led/lib/python3.7/site-packages/torch/distributed/launch.py,添加一个配置,笔者命名为torchrun,在Script path一列选择launch.py,参数

在torchrun等方式下,我们可以看到其实有多个进程或线程启动,而默认的调试窗口只能提供主进程的代码流程断点,此时需要看启动进程的pid

根据pid绑定到对应的进程上


可以看到断点可以断住第二块卡的程序了

测试代码,启动方式torchrun

import timeimport torch
import torch.distributed as dist
import torch.nn as nn
import torch.optim as optimfrom torch.nn.parallel import DistributedDataParallel as DDPclass ToyModel(nn.Module):def __init__(self):super(ToyModel, self).__init__()self.net1 = nn.Linear(10, 10)self.relu = nn.ReLU()self.net2 = nn.Linear(10, 5)def forward(self, x):return self.net2(self.relu(self.net1(x)))def demo_basic():dist.init_process_group("nccl")rank = dist.get_rank()print(f"Start running basic DDP example on rank {rank}.")# create model and move it to GPU with id rankdevice_id = rank % torch.cuda.device_count()model = ToyModel().to(device_id)time.sleep(10)print("DDP model init start...")ddp_model = DDP(model, device_ids=[device_id])print("DDP model init end...")loss_fn = nn.MSELoss()optimizer = optim.SGD(ddp_model.parameters(), lr=0.001)optimizer.zero_grad()outputs = ddp_model(torch.randn(20, 10))labels = torch.randn(20, 5).to(device_id)loss_fn(outputs, labels).backward()optimizer.step()if __name__ == "__main__":demo_basic()

注意:强制终止DDP的程序可能会使得显存占用未释放,此时需要找出nccl监听的端口,例如笔者是29500

附:参考链接

DP与DDP的区别:https://zhuanlan.zhihu.com/p/343951042?utm_id=0
DDP初始化:https://www.cnblogs.com/rossiXYZ/p/15584032.html
常见卡死问题:https://blog.csdn.net/weixin_42001089/article/details/122733667
https://www.cnblogs.com/azureology/p/16632988.html
https://github.com/IDEA-CCNL/Fengshenbang-LM/issues/123
NCCL:https://zhuanlan.zhihu.com/p/667221519
NCCL参数:https://zhuanlan.zhihu.com/p/661597951
init_process_group:https://blog.csdn.net/m0_37400316/article/details/107225030
参数检测:https://blog.csdn.net/weixin_46552088/article/details/138687997
分布式训练架构:https://zhuanlan.zhihu.com/p/689464092
https://zhuanlan.zhihu.com/p/706298084

相关文章:

pytorch多GPU训练教程

pytorch多GPU训练教程 文章目录 pytorch多GPU训练教程1. Torch 的两种并行化模型封装1.1 DataParallel1.2 DistributedDataParallel 2. 多GPU训练的三种架构组织方式2.2 数据不拆分&#xff0c;模型拆分&#xff08;Model Parallelism&#xff09;2.3 数据拆分&#xff0c;模型…...

力扣--LCR 178.训练计划VI

题目 教学过程中&#xff0c;教练示范一次&#xff0c;学员跟做三次。该过程被混乱剪辑后&#xff0c;记录于数组 actions&#xff0c;其中 actions[i] 表示做出该动作的人员编号。请返回教练的编号。 示例 1&#xff1a; 输入&#xff1a;actions [5, 7, 5, 5] 输出&#…...

Linux 网络接口配置

在 Linux 中,网络接口配置文件用于控制系统中的软件网络接口,并通过接口实现对网络设备的控制。当系统启动时,系统通过这些接口配置文件决定启动哪些接口,以及如此对这些接口进行配置. 在 Linux 中,网络接口配置文件用于控制系统中的软件网络接口,并通过这些接口实现对网络…...

【从零开始入门unity游戏开发之——C#篇01】理论开篇

文章目录 前言前置条件什么是编程&#xff1f;什么是代码&#xff1f;什么是编程语言&#xff1f;常见的编程语言什么是C#&#xff1f;学习Unity为什么要先学习C#&#xff1f;选择适合自己的IDE集成开发环境VSCode安装和环境配置VSCode调试模式专栏推荐完结 前言 这个系列我想…...

ABAP开发-批量导入BAPI和BDC_1

系列文章目录 文章目录 系列文章目录[TOC](文章目录) 前言一、概念二、BDC和BAPI数据导入1、BDC数据导入&#xff08;录屏&#xff09;2、BAPI数据导入 三、实例1、BAPI2、BDC 总结 前言 一、概念 SAP中&#xff0c;对一个事务码反复操作并且达到批量处理数据的效果&#xff0…...

RabbitMQ七种工作模式之 RPC通信模式, 发布确认模式

文章目录 六. RPC(RPC通信模式)客户端服务端 七. Publisher Confirms(发布确认模式)1. Publishing Messages Individually(单独确认)2. Publishing Messages in Batches(批量确认)3. Handling Publisher Confirms Asynchronously(异步确认) 六. RPC(RPC通信模式) 客⼾端发送消息…...

并非传统意义上的整体二分

是的&#xff0c;如标题所见&#xff0c;本文章会以作者所理解的整体二分思想来介绍一系列整体二分食用方法。 一下内容均是作者本人理解&#xff0c;可能会与算法本身冲突。 1 本质 1.1 板子及从中的启发 我们在做主席树板子的时候&#xff0c;如果使用整体二分&#xff0…...

PostgreSQL的一主一从集群搭建部署 (同步)

一、实验环境 虚拟机名IP身份简称keep-postgres12-node1192.168.122.87主节点node1keep-postgres12-node2192.168.122.89备节点node2 二、安装数据库 源码包方式&#xff08;主&#xff09; 1、创建用户 [rootkeep-postgres12-node1 ~]# groupadd postgres [rootkeep-post…...

ios逆向某新闻 md5+aes

本期的案例比较简单&#xff0c;也许是ios逆向算法本来就比较简单的原因&#xff0c;所以前面我就多扯一些爬虫和逆向的东西。之前写的文章都是js逆向和android逆向的案例&#xff0c;这也是首篇ios的案例&#xff0c;所以会从入门开始讲起。 3大逆向对比 首先爬虫工程师大部…...

grpc的负载均衡

grpc的负载均衡分为client-side load balance和server-side load balance。 所谓的“客户端负载均衡”是指主调方调用被调方的时候&#xff0c;在grpc.DialContext里需要指定grpc.WithDefaultServiceConfig&#xff0c;这个DefaultServiceConfig默认是用pick-first策略。也支持…...

提升搜索体验!—— 推出 Elastic Rerank 模型(技术预览版)

作者&#xff1a;来自 Elastic Shubha Anjur Tupil 几分钟内即可开始使用 Elastic Rerank 模型&#xff1a;强大的语义搜索功能&#xff0c;无需重新索引&#xff0c;提供灵活性和成本控制&#xff1b;高相关性、顶级性能和文本搜索效率。 使用我们全新的先进跨编码器 Elastic …...

【51单片机】程序实验1112.外部中断-定时器中断

主要参考学习资料&#xff1a;B站【普中官方】51单片机手把手教学视频 前置知识&#xff1a;C语言 单片机套装&#xff1a;普中STC51单片机开发板A4标准版套餐7 码字不易&#xff0c;求点赞收藏加关注(•ω•̥) 有问题欢迎评论区讨论~ 目录 程序实验11&12.外部中断-定时器…...

webrtc-java:引领Java进入实时通信新时代

webrtc-java&#xff1a;引领Java进入实时通信新时代 项目地址:https://gitcode.com/gh_mirrors/we/webrtc-java 在现代互联网应用中&#xff0c;实时通信&#xff08;Real-Time Communication, RTC&#xff09;已成为连接人们的桥梁。而说起RTC技术的先锋&#xff0c;不得不…...

TongWeb7-东方通快速使用手册

TongWeb7-东方通 快速使用手册 文章目录 第1章 TongWeb7 产品介绍 1.1 概述1.2 规范支持 第2章 TongWeb7 安装 2.1 TongWeb7 安装要求 2.1.1 TongWeb7 支持的操作系统2.1.2 系统要求2.1.3 其他 2.2 安装TongWeb72.3TongWeb7 目录结构说明2.4 TongWeb7 的启动和停止 第3章 应用…...

JVM内存区块

大家好&#xff0c;经过前两篇文章的介绍&#xff0c;大家对数组也有了一定了解&#xff0c;其实所有的数组都是对象&#xff0c;我们在方法中引用数组的变量叫做引用变量&#xff08;简称引用&#xff09;&#xff0c;那么数组到底是存放在哪里的呢&#xff0c;为什么引用再出…...

C语言单元总结

黑色加粗表示刷题刷到这样的题 红色加粗表示可能重要 单元一 程序设计宏观认识 C语言程序框架 C语言程序最基本的程序框架由两部分构成&#xff0c;分别是 1) 编译预处理 2) 函数组 C语言程序构成 C程序最大的特点就是所有的程序都是用函数来装配的&#xff0c;函数是构成…...

通过PS和Unity制作2D动画之一:创建形象

1、通过路径画出轮廓 使用路径的过程中&#xff0c;需要注意&#xff1a; 1&#xff09;如果使用形状工具作图&#xff0c;比如使用椭圆工具画正圆形&#xff0c;需要设置其属性为“路径”。 2&#xff09;使用路径选择工具&#xff0c;再按住Alt键点击某个路径&#xff0c;可…...

Notable是一款优秀开源免费的Markdown编辑器

一、Notable简介 ‌ Notable‌是一款开源的跨平台Markdown编辑器&#xff0c;支持Linux、MacOS、Windows以及国产操作系统等多种主流操作系统。它以其高颜值和强大的功能&#xff0c;成为了许多用户的首选工具。 主要特性 实时预览‌&#xff1a; Notable提供了实时预览功能&…...

基于MFC绘制门电路

MFC绘制门电路 1. 设计内容、方法与难点 本课题设计的内容包括了基本门电路中与门和非门的绘制、选中以及它们之间的连接。具体采用的方法是在OnDraw函数里面进行绘制&#xff0c;并设计元器件基类&#xff0c;派生出与门和非门&#xff0c;并组合了一个引脚类&#xff0c;在…...

C—指针初阶(2)

如果看完阁下满意的话&#xff0c;能否一键三连呢&#xff0c;我的动力就是大家的支持与肯定&#xff0c;冲&#xff01; 二级指针 我们先看概念以及作用&#xff1a;用来存放一级指针的地址的指针 先看例子&#xff0c;我们逐一分析 我们先分析上面那个“1” 标注那里&#x…...

Linux 基础环境的开发工具以及使用(下)

1. make / Makefile 自动化构建的工具 1&#xff09;引入 在我们进行一些大型的工程的时候&#xff0c;代码量是极其大&#xff0c;当我们代码在进行一系列的编译的时候&#xff0c;难免会出现一些错误&#xff0c;当我们对错误进行一系列的更改之后&#xff0c;难道我们需要…...

constexpr、const和 #define 的比较

constexpr、const 和 #define 的比较 一、定义常量 constexpr 定义&#xff1a;constexpr用于定义在编译期可求值的常量表达式。示例&#xff1a;constexpr int x 5;这里&#xff0c;x的值在编译期就确定为5。 const 定义&#xff1a;const表示变量在运行期间不能被修改&…...

期末复习-Hadoop综合复习

说明 以下内容仅供参考&#xff0c;提到不代表考到&#xff0c;请结合实际情况自己复习 目录 说明 一、题型及分值 二、综合案例题-部署Hadoop集群 或 部署Hadoop HA集群 案例 1&#xff1a;Hadoop 基础集群部署 案例 2&#xff1a;Hadoop HA 集群部署 案例 3&#xff…...

禁用SAP Hana错误密码锁定用户功能

背景 公司项目适配多种数据库其中包含SAP Hana&#xff0c;由于有同事的数据库连接工具保存了某个在用的数据库的旧密码&#xff0c;导致时不时会被锁用户。通过查询官方文档已解决&#xff0c;这里统一记录一下。 禁用密码锁定方法 以下按系统管理员和普通用户的解法分别列…...

Ubuntu 22.04加Windows AD域

说明&#xff1a;   Ubuntu 22.04系统通过realmd&#xff0c;sssd加入到 Active Directory 域&#xff0c;并为域用户配置sudo权限。同时为方便用户使用为Ubuntu系统安装wps与sogou中文输入法。 1. Ubuntu 22.04加入Windows AD域 1.1 首先配置网络&#xff0c;Ubuntu系统能…...

qt实现窗口的动态切换

先说一下整体思路。页面布局两个widget然后再将定时器和按钮关联起来。 定时器发出信号的时候&#xff0c;随着信号&#xff0c;不断地重新设置widget的宽度&#xff0c;实现窗口的动态切换。 具体操作如下&#xff1a; class QtWidgetsApplication4 : public QMainWindow {…...

第十七届山东省职业院校技能大赛 中职组“网络安全”赛项资源任务书样题②

第十七届山东省职业院校技能大赛 中职组“网络安全”赛项资源任务书样题② 模块A 基础设施设置与安全加固(200分)A-1 登录安全加固&#xff08;Windows, Linux&#xff09;A-2 Nginx安全策略&#xff08;Linux&#xff09;A-3日志监控&#xff08;Windows&#xff09;A-4中间件…...

【Vulkan入门】09-CreateFrameBuffer

目录 先叨叨git信息关键代码VulkanEnv::FindHostVisitbaleMemoryTypeIndex()TestPipeLine::CreateFramebuffers() 与网上大多数文章不同&#xff0c;其他文章基本上都使用窗口框架&#xff08;X11、GLFW、WSL等&#xff09;提供的surface来显示Vulkan渲染出的图像。我认为那样会…...

FPGA设计-Vivado的Off-Chip Termination设置问题

目录 简介: 设置规则: output strength(输出驱动器的电流驱动能力) slew rate(输出电压压摆率) Pull type(上下拉类型) On-chip termination(输入端/输出端的内置片上端接电阻) 输出端接电阻配置 简介: 经常遇到在FPGA设计时,很多人很迷惑这些关于硬件的终…...

GC常见垃圾回收算法,JVM分代模型

如何判断是垃圾&#xff1f;引用计数器和Root可达性算法 如何进行清除&#xff1f;标记清除、复制、标记整理 堆分代模型&#xff1f;Eden&#xff0c;Surevivor&#xff0c;Tenuring 一个对象从创建到消亡的过程&#xff1f; 对象什么时候进入老年代&#xff1f; 一、GC&a…...

外网设计素材网站/制造企业网站建设

根据前面的文章&#xff0c;我们会发现我们会在很多类前面加很多XLua的标签&#xff0c;有LuaCallCSharp&#xff0c;CSharpCallLua&#xff0c;Hotfix 等等。关于这些配置的作用官方文档也有相应的说明&#xff1a;https://github.com/Tencent/xLua/blob/master/Assets/XLua/D…...

医院网站可信认证必须做吗/互联网产品推广

最近&#xff0c;跟一个同行朋友小张聊天&#xff0c;他非常苦恼&#xff0c;因为工作不如意&#xff0c;他入职这个企业已经3年了&#xff0c;做的是网络工程师&#xff0c;薪资不高&#xff0c;公司事情还一大堆&#xff0c;还经常被迫背锅&#xff0c;眼看一把年纪了&#x…...

公司网站建设需求书/亚马逊排名seo

在JMeter BeanShell 前置处理器中&#xff0c;您可以使用下面的代码来定义长度为2的数组&#xff1a; int[] myArray new int[2]; myArray[0] 1; myArray[1] 2;该代码创建了一个名为"myArray"的整型数组&#xff0c;并初始化为具有两个元素&#xff0c;分别为1和2。…...

dtcms网站开发教程/抖音十大搜索关键词

SpringBoot项目的一个功能开发完成之后&#xff0c;需要对功能做单元测试&#xff0c;需要项目有单元测试的功能&#xff0c;这个项目是一个新建的项目&#xff0c;所以需要自己弄&#xff0c;下面记载一下步骤。 首先&#xff0c;我们使用点击需要做单元测试的类名&#xff0…...

wordpress代码添加/智能建站平台

问题简述&#xff1a;登录MSSQLSERVER的时候&#xff0c;如果输入ip而导致无法登录&#xff0c;可以参考一下步骤&#xff0c;设置完成后即可使用ip登录数据库step1:step2:step3:step4:step5:解决MSSQLSERVER连接服务器时候&#xff0c;输入IP无法连接的问题问题描述&#xff1…...

模板王网站/查网址

原文博客地址: Hexo博客多台电脑设备同步管理最近一直在折腾Hexo博客, 玩的可谓是不亦乐乎啊; 这里就整理一下之前遗留的一些问题和一些个性化配置如有遇到搭建个人博客时遇到的问题, 这里可参考我的之前的两篇相关博客 基于GitHub和Hexo搭建个人博客NexT主题配置优化-出土指南…...