cuda学习笔记(3)

一 CPU和GPU的区别

在这里插入图片描述

衡量处理器优劣的重要的两个指标:
延时性:同量的数据,所需要的处理时间
吞吐性:处理速度不快,但是每次处理量很大
GPU设计理念是最大化吞吐量,使用很小的控制单元对应很小的内存
cpu的设计理念:强大的控制单元和缓存单元

LocalCache将数据存储在内存中,因此可以快速访问缓存数据,提高应用程序的性能。LocalCache适用于许多不同的使用场景,特别是以下几种情况:
1.频繁访问的数据:如果应用程序中有一些频繁被访问的数据,将这些数据存储在LocalCache中可以大大提高访问速度。由于数据存储在内存中,相比于从磁盘或网络中读取数据,从本地缓存中获取数据的速度更快
在这里插入图片描述

CPU的理念:
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/94f03ea6b1734a60a460f5aa4b79e4e4.png在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

二 cuda编程

1 cuda运行效率

h开头表示是在cpu上的数据,
d开头表示在GPU上的数据
在这里插入图片描述
线程块是GPU运行的最小单元,线程块里面的东西不好会被打散
在这里插入图片描述
在这里插入图片描述
数据读取速度的比较,基于此,如果读取的数据很少,但是处理的数据的计算量很大,这种情况的计算效率就是最高的
在这里插入图片描述在这里插入图片描述
合并全局内存:推荐的数据读取方式是连读位置读取数据,速度是最快的;数据的存储也是连续位置
在这里插入图片描述
避免线程发散:
(1)避免同一个线程块或者kernel中执行不同的代码,因为不同代码之间的运行所需时间是不一样的,但是线程块又要求同步机制,程序之间彼此会相互等待,会影响程序效率
(2)循环长度不一致
在这里插入图片描述在这里插入图片描述

2 理解同步性

前面提到,Block里面的线程运行是同步的,不同kernel各自运行是同步的,kenelA内的东西全部运行结束之后才会运行kernel B,Block的线程同步是需要使用者自己来控制,kernel上的同步运行是GPU自己来实现的
在这里插入图片描述
在这里插入图片描述

3 硬件和软件之间的对应关系

(1)SM是流处理器

kernel:核,可以理解为c/c++里面的一个函数function,紫色的就是一个个线程
一个GPU包含若干SM
在这里插入图片描述

4 kernel的不同加载方式

首先需要清楚自己电脑的性能,知道自己电脑的能承受的最大线程数,每个处理器的最大线程数,每个block的最大线程数,
也可以使用代码,自己去获取计算配置参数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5 cuda如何调用内存

(1)调用局部变量,也就是本地变量

在这里插入图片描述

(2)调用全局变量

都是传递指针变量
前半段是自定义
后半段是使用,使用的时候,host表示主机,CPU,device表示GPU,使用的时候需要在GPU上先分配呢内存,然后将主机上的数据拷贝到GPU上,然后加载核函数进行运算,最后再将GPU上运算完毕的数据拷贝回CPU
在这里插入图片描述

(3)共享变量的调用

共享变量是每一个线程都在往里面的指定位置写数据,存在一个时间差的问题,就需要加同步机制
在这里插入图片描述

共享数据,三个参数,的含义依次如下
在这里插入图片描述

(4)同步操作----原子操作,有些系统不支持,需要自己去实现

在这里插入图片描述

(4)同步操作---- 同步函数: _syncthreads()
(5)同步操作---- 同步函数: _threadfence() 以及——threadfence_block()

在这里插入图片描述

(5)同步操作---- 同步函数: CPU和GPU同步

主要在主代码里面使用
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

案例1 计算1-7的各自平方


#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>



__global__ void square(float* d_out, float* d_in)
{
	int idx = threadIdx.x;
	float f = d_in[idx];
	d_out[idx] = f * f;
}


int main(int argc, char** argv)
{
	const int ARRAY_SIZE = 8;
	const int ARRAY_BITE = ARRAY_SIZE * sizeof(float);

	//**************************在cpu上输入数据 *********************
	float h_in[ARRAY_SIZE];  //h_in表示存在cpu上的输入数据, 
	for (int i = 0; i < ARRAY_SIZE; i++)
	{
		h_in[i] = float(i);
	}
	float h_out[ARRAY_SIZE]; //h_out用来存储GPU处理完之后传回cpu上的数据

	//**************************在GPU上分配内容空间,空间和CPU上数据空间大小一样 *********************
	float* d_in;      //用来存储从CPU传到GPU上的待处理数据
	float* d_out;     //用来存储GPU最终处理完的数据
	cudaMalloc((void**)&d_in, ARRAY_BITE);
	cudaMalloc((void**)&d_out, ARRAY_BITE);

	**************************把cpu上的待处理数据复制到GPU上 *********************
	cudaMemcpy(d_in, h_in, ARRAY_BITE, cudaMemcpyHostToDevice);

	//*****启动加载kernel到GPU,所谓kernel,在这里就是square函数,这个函数是要在GPU上进行实现的 *********************
	square << <1, ARRAY_SIZE >> > (d_out, d_in);  //使用1个线程块,每个线程块有 ARRAY_SIZE个线程,(d_out, d_in)是函数square的输入参数

	//**************************将在GPU上处理完的数据复制到CPU上 *********************
	cudaMemcpy(h_out, d_out, ARRAY_BITE, cudaMemcpyDeviceToHost);

	for (int i = 0; i < ARRAY_SIZE; i++)
	{
		printf("%f", h_out[i]);
		printf("%\n");
	}

	cudaFree(d_in);
	cudaFree(d_out);

	return 0;
}

在这里插入图片描述

案例2 归约,求和运算,对1+2+3+…

归约:多个输入但是最后只有一个输出

**
#include <stdio.h>
#include <stdlib.h>
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
//#include <device_functions.h>

using namespace std;
__global__ void global_reduce_kernel(float* d_out, float* d_in)
{
    int myId = threadIdx.x + blockDim.x * blockIdx.x;  //有多个block.在所有线程里面的位置,全局变量的位置
    int tid = threadIdx.x; //在当前block里面的位置

    // do reduction in global mem
    //	//循环的条件是 s 大于 0,每次循环迭代结束后,s 的值右移一位(相当于将其除以 2),以便在下一次迭代中处理更小的数据块
//	//这里是实现每一个block里面线程的对半累加
    for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1)
    {
        if (tid < s)
        {
            d_in[myId] += d_in[myId + s];
        }
        __syncthreads();        // make sure all adds at one stage are done! //每个线程块每次循环结束之后才进行下一次运行
    }

    //最后要的是线程块的所有计算的求和结果
    // only thread 0 writes result for this block back to global mem
    if (tid == 0)   //等于0说明当前block的所有线程对折运算结束
    {
        d_out[blockIdx.x] = d_in[myId];
    }
}

使用共享内存实现归约
__global__ void shmem_reduce_kernel(float* d_out, const float* d_in)
{
    // sdata is allocated in the kernel call: 3rd arg to <<<b, t, shmem>>>
    extern __shared__ float sdata[];  //给每一个block定义他们各自的内存;

    int myId = threadIdx.x + blockDim.x * blockIdx.x;   //有多个block.在所有线程的位置
    int tid = threadIdx.x;

    // load shared mem from global mem
    //	//然后将全局内存的数据复制给共享内存, 之后就不需要再从全局内存读数据,
//	//共享数据读取的速度快于全局内存
    sdata[tid] = d_in[myId];
    __syncthreads();            // make sure entire block is loaded!

    // do reduction in shared mem
    for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1)
    {
        if (tid < s)
        {
            sdata[tid] += sdata[tid + s];
        }
        __syncthreads();        // make sure all adds at one stage are done!
    }

    // only thread 0 writes result for this block back to global mem
    if (tid == 0)
    {
        d_out[blockIdx.x] = sdata[0];
    }
}

void reduce(float* d_out, float* d_intermediate, float* d_in,
    int size, bool usesSharedMemory)
{
    // assumes that size is not greater than maxThreadsPerBlock^2
    // and that size is a multiple of maxThreadsPerBlock
    const int maxThreadsPerBlock = 1024;
    int threads = maxThreadsPerBlock;
    int blocks = size / maxThreadsPerBlock;
    if (usesSharedMemory)
    {
        shmem_reduce_kernel << <blocks, threads, threads * sizeof(float) >> >
            (d_intermediate, d_in);
    }
    else
    {
        global_reduce_kernel << <blocks, threads >> >
            (d_intermediate, d_in);
    }
    // now we're down to one block left, so reduce it
    //	//这里的blocks设为1使因为,假设有1024个线程块,每个线程块有1024个线程,之前在每个线程块里面完成了各自的对半加,最后每个线程块将得到
//	//一个数据,总的得到1024个数据,刚好放置在一个block里面完成最后的对半累加
    threads = blocks; // launch one thread for each block in prev step
    blocks = 1;
    if (usesSharedMemory)
    {
        shmem_reduce_kernel << <blocks, threads, threads * sizeof(float) >> >
            (d_out, d_intermediate);
    }
    else
    {
        global_reduce_kernel << <blocks, threads >> >
            (d_out, d_intermediate);
    }
}

int main(int argc, char** argv)
{
    int deviceCount;
    cudaGetDeviceCount(&deviceCount);
    if (deviceCount == 0) {
        fprintf(stderr, "error: no devices supporting CUDA.\n");
        exit(EXIT_FAILURE);
    }
    int dev = 0;
    cudaSetDevice(dev);

    cudaDeviceProp devProps;
    if (cudaGetDeviceProperties(&devProps, dev) == 0)
    {
        printf("Using device %d:\n", dev);
        printf("%s; global mem: %dB; compute v%d.%d; clock: %d kHz\n",
            devProps.name, (int)devProps.totalGlobalMem,
            (int)devProps.major, (int)devProps.minor,
            (int)devProps.clockRate);
    }

    const int ARRAY_SIZE = 1 << 10;
    const int ARRAY_BYTES = ARRAY_SIZE * sizeof(float);

    // generate the input array on the host
    float h_in[ARRAY_SIZE];
    float sum = 0.0f;
    for (int i = 0; i < ARRAY_SIZE; i++) {
        // generate random float in [-1.0f, 1.0f]
        h_in[i] = -1.0f + (float)rand() / ((float)RAND_MAX / 2.0f);
        printf("%f ", h_in[i]);
        sum += h_in[i];
    }

    // declare GPU memory pointers
    float* d_in, * d_intermediate, * d_out;

    //	//在GPU上创建存储待处理数据和处理结果的数组
    // allocate GPU memory
    cudaMalloc((void**)&d_in, ARRAY_BYTES);
    cudaMalloc((void**)&d_intermediate, ARRAY_BYTES); // overallocated
    cudaMalloc((void**)&d_out, sizeof(float));

    //	//将CPU输入数据输入到GPU
    // transfer the input array to the GPU
    cudaMemcpy(d_in, h_in, ARRAY_BYTES, cudaMemcpyHostToDevice);

    int whichKernel = 0;
    if (argc == 2) {
        whichKernel = atoi(argv[1]);
    }

    cudaEvent_t start, stop;
    cudaEventCreate(&start);
    cudaEventCreate(&stop);
    // launch the kernel
    switch (whichKernel) {
    case 0:
        printf("Running global reduce\n");
        cudaEventRecord(start, 0);
        for (int i = 0; i < 100; i++)
        {
            reduce(d_out, d_intermediate, d_in, ARRAY_SIZE, false);
        }
        cudaEventRecord(stop, 0);
        break;
    case 1:
        printf("Running reduce with shared mem\n");
        cudaEventRecord(start, 0);
        for (int i = 0; i < 100; i++)
        {
            reduce(d_out, d_intermediate, d_in, ARRAY_SIZE, true);
        }
        cudaEventRecord(stop, 0);
        break;
    default:
        fprintf(stderr, "error: ran no kernel\n");
        exit(EXIT_FAILURE);
    }

    cudaEventSynchronize(stop);
    float elapsedTime;
    cudaEventElapsedTime(&elapsedTime, start, stop);
    elapsedTime /= 100.0f;      // 100 trials

    // copy back the sum from GPU
    float h_out;
    cudaMemcpy(&h_out, d_out, sizeof(float), cudaMemcpyDeviceToHost);

    printf("average time elapsed: %f\n", elapsedTime);

    // free GPU memory allocation
    cudaFree(d_in);
    cudaFree(d_intermediate);
    cudaFree(d_out);

    return 0;
}
**

案例3 扫描并行,也是实现求和运算,但是使用场景不同,使用场景是每输入一个数,完成当数和之前所有数据的累加 ??

算法思想:从n = 0,1,2,…依次以0,2^n 然后为间隔做累加,如下图,第一次累加是以0为间隔,相邻两个数做累加,
0前面没有可以和他直接相加的数,所以直接搬下去,第二次累加是以1为间隔的两个数做累加,0,1,前面没有和累加的数,所以,0,1,直接搬下去
在这里插入图片描述


#include <stdio.h>
#include <stdlib.h>
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
//#include <device_functions.h>

using namespace std;
__global__ void global_scan_kernel(float* d_out, float* d_in)
{
    int idx = threadIdx.x; //在当前block里面的位置

    float out = 0.00f;
    d_out[idx] = d_in[idx];
    __syncthreads();  //这里同步是希望上面的赋值操作全部完成之后,才能开始下面的操作,这是扫描计算的前提,所有数据都要准备好

    for (int interval = 1; interval < sizeof(d_in); interval *= 2)
    {
        if (idx - interval >= 0)
        {
            out = d_out[idx] + d_out[idx - interval];
        }
        __syncthreads();   //当前所有数据计算完毕,才能进入下一轮的计算,也就是要求每一轮的数据都是准备完毕的

        if (idx - interval >= 0)
        {
            d_out[idx] = out;
            out = 0.00f;
        }
    }
}

__global__ void shmem_scan_kernel(float* d_out, const float* d_in)
{
    // sdata is allocated in the kernel call: 3rd arg to <<<b, t, shmem>>>
    extern __shared__ float sdata[];  //给每一个block定义他们各自的内存;

    int idx = threadIdx.x; //在当前block里面的位置
    sdata[idx] = d_in[idx];
    float out = 0.00f;

    __syncthreads();            // make sure entire block is loaded!
    for (int interval = 1; interval < sizeof(d_in); interval *= 2)
    {
        if (idx - interval >= 0)
        {
            out = sdata[idx] + sdata[idx - interval];
        }

        __syncthreads();   //当前所有数据计算完毕,才能进入下一轮的计算,也就是要求每一轮的数据都是准备完毕的

        if (idx - interval >= 0)
        {
        //这里为什么能直接把out赋值到idx索引,因为在此之前加了同步语句,
       // 也就是多个线程同时运行,同时执行out = sdata[idx] + sdata[idx - interval];语句,
        //然后计算完毕就同时存在多个out,所以才能把各自的out赋值到idx,至于为什么要存到idx索引,
        //是因为算法需要它存到对应的位置
            sdata[idx] = out;
            out = 0.00f;
            //?????????????????????????  为什么打印不了中间过程
            //printf("*************\n");
            //printf("%f  ", sdata[idx]);
            //printf("*************\n");  
        }
    }
    d_out[idx] = sdata[idx];
}


int main(int argc, char** argv)
{
    int deviceCount;
    cudaGetDeviceCount(&deviceCount);
    if (deviceCount == 0) {
        fprintf(stderr, "error: no devices supporting CUDA.\n");
        exit(EXIT_FAILURE);
    }
    int dev = 0;
    cudaSetDevice(dev);

    cudaDeviceProp devProps;
    if (cudaGetDeviceProperties(&devProps, dev) == 0)
    {
        printf("Using device %d:\n", dev);
        printf("%s; global mem: %dB; compute v%d.%d; clock: %d kHz\n",
            devProps.name, (int)devProps.totalGlobalMem,
            (int)devProps.major, (int)devProps.minor,
            (int)devProps.clockRate);
    }

    const int ARRAY_SIZE = 8;  //数字1 << 左移,1 << i = pow(2,i)
    const int ARRAY_BYTES = ARRAY_SIZE * sizeof(float);

    // generate the input array on the host
    float h_in[ARRAY_SIZE];
    printf("-------------input-----------\n ");
    for (int i = 0; i < ARRAY_SIZE; i++) {
        // generate random float in [-1.0f, 1.0f]
        h_in[i] = i;
        printf("%f  ", h_in[i]);
    }

    // declare GPU memory pointers
    float* d_in, * d_out;

    //在GPU上创建存储待处理数据和处理结果的数组
    // allocate GPU memory
    cudaMalloc((void**)&d_in, ARRAY_BYTES);
    cudaMalloc((void**)&d_out, ARRAY_BYTES);

    //	//将CPU输入数据输入到GPU
    // transfer the input array to the GPU
    cudaMemcpy(d_in, h_in, ARRAY_BYTES, cudaMemcpyHostToDevice);


    cudaEvent_t start, stop;
    cudaEventCreate(&start);  //用于创建事件,用于测量GPU操作的时间
    cudaEventCreate(&stop);
 

    int whichKernel = 1;
    if(!whichKernel)
    //global_scan_kernel << <blocks, threads >> > (d_in);
       global_scan_kernel << <1, ARRAY_SIZE >> > (d_out,d_in);
    else
       shmem_scan_kernel << <1, ARRAY_SIZE,ARRAY_SIZE*sizeof(float) >> > (d_out, d_in);
   
    // copy back the sum from GPU
    float h_out[ARRAY_SIZE];
    cudaMemcpy(h_out, d_out, ARRAY_BYTES, cudaMemcpyDeviceToHost);


    cudaEventSynchronize(stop);
    float elapsedTime;
    cudaEventElapsedTime(&elapsedTime, start, stop);
    elapsedTime /= 100.0f;      // 100 trials


    printf("\n");
    if (whichKernel == 0)
    {
        printf("global_scan_kernel\n");
    }
    else
    {
        printf("share_scan_kernel\n");
    }
    printf("-------------out-----------\n "); 
    for (int i = 0; i < ARRAY_SIZE; i++) {
        // generate random float in [-1.0f, 1.0f]
        printf("%f ", h_out[i]);
    }
    printf("-------------out-----------\n ");
    printf("\n");
    printf("average time elapsed: %f\n", elapsedTime);

    // free GPU memory allocation
    cudaFree(d_in);
    cudaFree(d_out);

    return 0;
}





在这里插入图片描述
在这里插入图片描述

案例4 直方图的并行计算

(1)错误1:对数据同时操作读和写 ??

下面这种写法,对于第一个bin来说,假设输入数据是1:66655,数据1和17都会同时读bin里面的初始计数,然后进行累加,正常来说应该是两个数据同时读了bin1的0,然后同时写一个1进去,最后结果总是1,但是可能机器会出问题,导致最多也就写一个2,先后加了1.
在这里插入图片描述

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/1e4f145d9a4c407fa8828aa467786fc0.png pic_center =700x)

(2)对于(1)的改进,用原子相加,将读写并行做成串口,数据1读写完成之后,17才能进行读写。这样处理的并行化程度是取决于bin的数量的(2)的并行主要在累加的地方,写入的时候是串行,如果bin很多,平摊下来的时间就短,并行化程度就高了。

AtomicAdd就是原子操作,原子操作就相当于各个线程排队操作。 bin的数量就相当于队列的数量,队列多了,肯定就快了,队列多,等待是并行的。
在这里插入图片描述

(3)局部直方图,读写本身就是串行的,

在这里插入图片描述
在这里插入图片描述


#include "cuda_runtime.h"
#include "device_launch_parameters.h"

#include <stdio.h>

//假设是8个block,8个线程,也就是每个block要处理16个数据
__global__ void local_histo(float* d_out, float* d_in, const int BIN_COUNYT, const int Threads_count) {
    int idx = threadIdx.x + blockDim.x*blockIdx.x;  //有多个block.在所有线程里面的位置
    int tid = threadIdx.x; //在当前block里面的位置
    //总共128个数,分成3个bin,但是先要分成8组同时用8个线程来对数据进行处理,也就是说每个线程处理16个数据,处理的结果最后各自形成各自的3个bin,
    //d_out里面,相连的三个数据认为是一组不重复且不连续的16个数的统计直方图,依次存储
    for (int interpre = 1; interpre < sizeof(d_in)/ Threads_count; interpre +=8)
    {
        int binID = d_in[idx] % BIN_COUNYT;
        d_out[tid] ++;
    }
}

int main(int argc, char** argv) {
    //**********************************
    int deviceCount;
    cudaGetDeviceCount(&deviceCount);
    if (deviceCount == 0) {
        fprintf(stderr, "error: no devices supporting CUDA.\n");
        exit(EXIT_FAILURE);
    }
    int dev = 0;
    cudaSetDevice(dev);

    cudaDeviceProp devProps;
    if (cudaGetDeviceProperties(&devProps, dev) == 0)
    {
        printf("Using device %d:\n", dev);
        printf("%s; global mem: %dB; compute v%d.%d; clock: %d kHz\n",
            devProps.name, (int)devProps.totalGlobalMem,
            (int)devProps.major, (int)devProps.minor,
            (int)devProps.clockRate);
    }
    //**********************************

    const int ARRAY_SIZE = 128;
    const int ARRAY_BYTES = ARRAY_SIZE * sizeof(float);

    // generate the input array on the host
    float h_in[ARRAY_SIZE];
    for (int i = 0; i < ARRAY_SIZE; i++) {
        h_in[i] = float(i);
    }
    float h_out[ARRAY_SIZE];

    // declare GPU memory pointers
    float* d_in;
    float* d_out;

    // allocate GPU memory
    cudaMalloc((void**)&d_in, ARRAY_BYTES);
    cudaMalloc((void**)&d_out, ARRAY_BYTES);

    // transfer the array to GPU
    cudaMemcpy(d_in, h_in, ARRAY_BYTES, cudaMemcpyHostToDevice);

    // launch the kernel
    int USED_threadNum = 8;
    int USED_BLOCK = 8;
    /*local_histo << <1, ARRAY_SIZE >> > (d_out, d_in);*/
    local_histo << < USED_BLOCK, threadNum >> > (d_out, d_in, 3, USED_threadNum)

    // copy back the result array to the GPU
    cudaMemcpy(h_out, d_out, ARRAY_BYTES, cudaMemcpyDeviceToHost);

    // print out the resulting array
    for (int i = 0; i < ARRAY_SIZE; i++) {
        printf("%f", h_out[i]);
        printf(((i % 4) != 3) ? "\t" : "\n");
    }

    // free GPU memory allocation
    cudaFree(d_in);
    cudaFree(d_out);

    return 0;


}

案例5 压缩与分配

在这里插入图片描述

稀疏型:52个线程同时运行,进行判读,不满足条件的就终止运算了,也就是说52个线程的运行时间是不相同的,有些线程中途会被闲置
密集型:先52个线程一起判断是不是方块;然后再用13个线程完成卡片的计算
在这里插入图片描述

案例6 分段扫描

对每个数据段里面的数据,实现各自的扫描
在这里插入图片描述

分段扫描的应用案例:稀疏矩阵的处理
在这里插入图片描述

案例7 排序

在这里插入图片描述
归并排序
在这里插入图片描述在这里插入图片描述

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

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

相关文章

二进制文件的膨胀策略和使用 debloat 消除膨胀测试

在恶意软件的分析中有的 Windows 可执行文件&#xff08;PE 文件&#xff09;会通过膨胀策略来绕过防病毒一些防病毒的检查&#xff0c;比如上传云进行分析&#xff0c;因为文件太大了所以无法进行一些防病毒分析。一般的可执行文件有很多的膨胀策略&#xff0c;一般简单的膨胀…

3 数据类型、运算符与表达式-3.3.2 整型变量(原码,反码,补码)

在计算机科学中&#xff0c;补码、原码和反码是用来表示带符号整数的二进制编码方法&#xff0c;特别是在计算机内存中存储和处理整数时。这些编码方式帮助计算机区分正数和负数&#xff0c;并支持算术运算。以下是它们的具体含义&#xff1a; 原码&#xff08;True Form or S…

【免杀】C2远控-Loader加载器-动态API调用

目录 创建后门程序站在杀毒程序立场上对后门进行分析例&#xff1a;动态调用VirtualProtect函数 作用:绕过杀毒对导入表的检测定性 创建后门程序 VS新建项目 回调函数加载Loader #include <Windows.h>unsigned char shellcode[] "";void CallBack() {void* p…

【LLM】Dify 0.6.10 在Windows系统上本地化部署

【LLM】Dify 0.6.10 在Windows系统上本地化部署 文章目录 【LLM】Dify 0.6.10 在Windows系统上本地化部署一、参考资料二、Dify 概述1、Dify开源项目功能介绍&#xff08;RAG流水线&#xff0c;Agent工具接入&#xff0c;Prompt配置和工作流编排&#xff0c;大模型接入&#xf…

使用Vue CLI在其他磁盘创建项目出现错误及解决

Vue CLI是Vue.js官方推出的脚手架工具&#xff0c;可以帮我们快速的创建Vue项目框架。 我们创建Vue项目时一般默认都是在C盘&#xff0c;但由于某些因素我们需要在其他磁盘上创建Vue项目。 通过“winr”打开终端时默认位置都是C盘&#xff0c;但是Vue CLI不接受绝对路径作为参…

OpenGL-ES 学习(6)---- Ubuntu OES 环境搭建

OpenGL-ES Ubuntu 环境搭建 此的方法在 ubuntu 和 deepin 上验证都可以成功搭建 目录 OpenGL-ES Ubuntu 环境搭建软件包安装第一个三角形基于 glfw 实现基于 X11 实现 软件包安装 sudo apt install libx11-dev sudo apt install libglfw3 libglfw3-dev sudo apt-get install…

python3.6ssl证书错误无法pip的问题

出现了这个报错&#xff1a; Could not fetch URL https://pypi.python.org/simple/cryptography/: There was a problem confirming the ssl certificate: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:748) - skipping 一开始以为是fiddler开着的原…

iOS——分类、扩展和关联对象

前情回顾 回顾一下什么是分类、什么是扩展&#xff1a; 分类&#xff08;Category&#xff09;和类扩展&#xff08;Extension&#xff09;是两种常见的代码组织方式&#xff0c;用于扩展类的功能。 分类&#xff08;Category&#xff09; 分类是一种将类的实现分散到多个源…

svn的使用

【图文详解】入职必备——SVN使用教程-CSDN博客 使用SVNBucket作为服务端,来辅助学习. 什么时候会产生冲突呢? 原本A,B,服务器的版本都一致,都是最新版. A修改文件m,向服务器提交 B修改文件m,向服务器提交,这时候出现了冲突 双击冲突的文件,手动修改

vscode 访问容器的方式

方法一&#xff1a;先连服务器&#xff0c;再转入容器 配置客户机A M1. 客户机A通过 vscode 连接服务器B&#xff0c;再连接容器C 配置vscode的ssh配置文件&#xff1a;~.ssh\config&#xff08;当需要多个不同的连接时&#xff0c;使用 IdentityFile 指定公钥位置&#xff09;…

【解决问题】QApplication: No such file or directory,C++ 使用Qt或项目未正确加载Cmake报错

运行环境&#xff1a; Clion编译&#xff0c;构建C工程项目报错QApplication: No such file or directory 问题描述 QApplication: No such file or directory 引用的#include <QApplication>飘红 解决方案 1、Qt没有安装正确&#xff0c;请使用对应版本的Qt。或编译…

【Java】Java流中的API

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

Vue笔记(二)

Vue&#xff08;一&#xff09;&#xff1a;Vue笔记&#xff08;一&#xff09;-CSDN博客 综合案例&#xff1a;水果购物车 项目功能&#xff1a; 视频链接&#xff1a;034-水果购物车-基本渲染_哔哩哔哩_bilibili 目录结构&#xff1a; index.css .app-container {padding-…

【python】flask 框架

python flask 框架 flask是一个轻量级的python后端框架 (Django, tornado, flask) 官网&#xff1a;欢迎来到 Flask 的世界 — Flask中文文档(3.0.x) 安装&#xff1a;pip install Flask -i https://pypi.douban.com 常识&#xff1a; http,默认端口号为80; https,默认端口号…

【Linux】进程间通信之命名管道

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 如果文章对…

linux centos如何安装python3版本但不能影响默认python2版本

在CentOS上安装Python3而不影响系统默认的Python2,具有如何安装呢? 1. 更新系统包 首先,确保系统包是最新的: sudo yum update -y2. 安装EPEL存储库 EPEL(Extra Packages for Enterprise Linux)存储库包含许多额外的软件包,包括Python3: sudo yum install epel-rel…

IDEA:配置Golang的开发环境

1、下载&安装 进入GO的官网下载对应的GO 我们可以下载安装版&#xff0c;不过本人习惯下载解压版&#xff0c;这个因个人而异 2、配置环境变量 GOBIN : %GOROOT%\bin GOPATH : D:\MyGo 工作区间 GOROOT : D:\Program Files\Go GOJDK地址PATH: %GOBIN% ; %GOROOT%\bin ; …

LeetCode 算法:矩阵置零c++

原题链接&#x1f517;&#xff1a;矩阵置零 难度&#xff1a;中等⭐️⭐️ 题目 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1…

stm32MP135裸机编程:修改基于SD卡的FSBL-A用户程序引导程序(boot)

0 参考资料 轻松使用STM32MP13x - 如MCU般在cortex A核上裸跑应用程序.pdf stm32mp135官方开发板原理图&#xff08;mb1635-bdp-v1-0.zip&#xff09; STM32Cube_FW_MP13_V1.0.0 STM32CubeIDE v1.15 1 为什么需要修改FSBL-A用户程序引导程序 FSBL-A用户程序引导程序的作用在《…

PR如何让音频淡入淡出

PR如何让音频淡入淡出 方法一&#xff1a;效果控件关键帧方法二&#xff1a;音频轨道关键帧 以淡入为例&#xff0c;介绍如何设置淡入的两种方法&#xff0c;推荐使用第二种。淡出效果类似。 方法一&#xff1a;效果控件关键帧 选中音频&#xff0c;点击效果控件 在淡入结束的…