缩放算法优化步骤详解

添加链接描述

背景

假设数据存放在在unsigned char* m_pData 里面,宽和高分别是:m_nDataWidth m_nDataHeight
给定缩放比例:fXZoom fYZoom,返回缩放后的unsigned char* dataZoom
这里采用最简单的缩放算法即:
根据比例计算原图和缩放后图坐标的对应关系:缩放后图坐标*缩放比例 = 原图坐标

原始代码 未优化

#pragma once
class zoomBlock
{
public:zoomBlock() {};~zoomBlock();void zoomDataSSE128(unsigned char* dataZoom, float  fXZoom, float fYZoom);void zoomData(unsigned char* dataZoom, float  fXZoom, float fYZoom);void test(float  fXZoom =0.5, float fYZoom=0.5);void init(int DataWidth, int DataHeight);
private:void computeSrcValues(int* srcValues, size_t size, float zoom, int dataSize);private:unsigned char* m_pData = nullptr;float m_fXZoom = 1 ;//x轴缩放比例  m_nXZoom=1时 不缩放float m_fYZoom = 1 ;//y轴缩放比例int m_nDataWidth = 0;int m_nDataHeight = 0;
};#include "zoomBlock.h"
#include <stdio.h>
#include <iostream>
#include<iomanip>
#define SAFE_DELETE_ARRAY(p) { if( (p) != NULL ) delete[] (p); (p) = NULL; }zoomBlock::~zoomBlock()
{SAFE_DELETE_ARRAY(m_pData);
}
void zoomBlock::init(int DataWidth, int DataHeight)
{m_nDataWidth = DataWidth;m_nDataHeight = DataHeight;m_pData = new unsigned char[m_nDataWidth* m_nDataHeight];for (int i = 0; i < m_nDataWidth * m_nDataHeight; ++i){m_pData[i] = static_cast<unsigned char>(i);  // Replace this with your data initialization logic}
}void zoomBlock::zoomData(unsigned char* dataZoom, float  fXZoom, float fYZoom)
{int nZoomDataWidth = fXZoom * m_nDataWidth;int nZoomDataHeight = fYZoom * m_nDataHeight;for (size_t row = 0; row < nZoomDataHeight; row++){for (size_t column = 0; column < nZoomDataWidth; column ++){//1int srcx = std::min(int(row / fYZoom), m_nDataHeight - 1);int srcy = std::min(int(column / fXZoom), m_nDataWidth - 1);//2int srcPos = srcx * m_nDataHeight + srcy;int desPos = row * nZoomDataHeight + column;dataZoom[desPos] = m_pData[srcPos];}}
}void zoomBlock::test(float  fXZoom, float fYZoom)
{init(8,8);std::cout << "Values in m_pData:" << std::endl;for (int i = 0; i < m_nDataWidth * m_nDataHeight; ++i){std::cout << std::setw(4) << static_cast<int>(m_pData[i]) << " ";if ((i + 1) % m_nDataWidth == 0) {  // Adjust the value based on your datastd::cout << std::endl;}}unsigned char* dataZoom = new unsigned char[fXZoom * m_nDataWidth * fYZoom * m_nDataHeight];zoomData(dataZoom, fXZoom, fYZoom);// Print or inspect the values in m_dataZoomint nZoomDataWidth = fXZoom * m_nDataWidth;int nZoomDataHeight = fYZoom * m_nDataHeight;std::cout << "Values in m_dataZoom:" << std::endl;for (int i = 0; i < nZoomDataHeight * nZoomDataWidth; ++i){std::cout << std::setw(4)<< static_cast<int>(dataZoom[i]) << " ";if ((i + 1) % nZoomDataWidth == 0) {  // Adjust the value based on your datastd::cout << std::endl;}}SAFE_DELETE_ARRAY(dataZoom);}

测试代码

int main()
{zoomBlock zoomBlocktest;zoomBlocktest.test(1.5,1.5);return 0;
}

在这里插入图片描述
其中函数
·void zoomBlock::zoomData(unsigned char* dataZoom, float fXZoom, float fYZoom)·
没有使用任何加速优化,现在来分析它。

sse128

我们知道sse128可以一次性处理4个int类型,所以我们把最后一层for循环改成,4个坐标的算法,不满4个的单独计算

void zoomBlock::zoomDataSSE128(unsigned char* dataZoom, float  fXZoom, float fYZoom)
{int nZoomDataWidth = fXZoom * m_nDataWidth;int nZoomDataHeight = fYZoom * m_nDataHeight;for (size_t row = 0; row < nZoomDataHeight; row++){int remian = nZoomDataWidth % 4;for (size_t column = 0; column < nZoomDataWidth - remian; column += 4){//第一个坐标int srcx = std::min(int(row / fYZoom), m_nDataHeight - 1);int srcy = std::min(int(column / fXZoom), m_nDataWidth - 1);int srcPos = srcx * m_nDataHeight + srcy;int desPos = row * nZoomDataHeight + column;dataZoom[desPos] = m_pData[srcPos];//第二个坐标int srcx1 = std::min(int((row+1) / fYZoom), m_nDataHeight - 1);int srcy1 = std::min(int((column+1) / fXZoom), m_nDataWidth - 1);int srcPos1 = srcx1 * m_nDataHeight + srcy1;int desPos1 = (row+1) * nZoomDataHeight + column+1;dataZoom[desPos1] = m_pData[srcPos1];//第3个坐标// 。。。//第4个坐标// 。。。}// Process the remaining elements (if any) without SSEfor (size_t column = nZoomDataWidth - remian; column < nZoomDataWidth; column++){int srcx = std::min(int(row / fYZoom), m_nDataHeight - 1);int srcy = std::min(int(column / fXZoom), m_nDataWidth - 1);int srcPos = srcx * m_nDataHeight + srcy;int desPos = row * nZoomDataHeight + column;dataZoom[desPos] = m_pData[srcPos];}}
}

上面 一次处理四个坐标的代码要改成sse的代码

在最里层的循环里面,每次都要计算 row / fYZoom 和 column / fXZoom,这个实际上可以挪出for循环,计算一次存到数组里

数据坐标desPos和srcPos ,必须放在最内存的循环里

所以我们用calculateSrcIndex函数单独处理 row / fYZoom 和 column / fXZoom,希望达到如下效果:

void calculateSrcIndex(int* srcValues, int size, float zoom,int max)
{for (int i = 0; i < size; i++){srcValues[i] = std::min(int(i/zoom),max);}
}

改成sse:

void calculateSrcIndex(int* srcValues, int size, float zoom,int max)
{__m128i mmIndex, mmSrcValue, mmMax;mmMax = _mm_set1_epi32(max);float zoomReciprocal = 1.0f / zoom;int remian = size % 4;for (size_t i = 0; i < size - remian; i += 4){mmIndex = _mm_set_epi32(i + 3, i + 2, i + 1, i);mmSrcValue = _mm_cvtps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(mmIndex), _mm_set1_ps(zoomReciprocal)));// Ensure srcValues are within the valid range [0, max]mmSrcValue = _mm_min_epi32(mmSrcValue, mmMax);// Store the result to the srcValues array_mm_storeu_si128(reinterpret_cast<__m128i*>(&srcValues[i]), mmSrcValue);}// Process the remaining elements (if any) without SSEfor (size_t i = size - remian; i < size; i++){srcValues[i] = std::min(int(i / zoom), max);}
}

解释:
这里主要处理int型数据,为了使用sse加速,要使用__m128i类型来存储4个int

加载int到__m128i:

  1. __m128i _mm_set1_epi32(int i);
    这个指令是使用1个i,来设置__m128i,将__m128i看做4个32位的部分,则每个部分都被赋为i;

  2. __m128i _mm_set_epi32(int i3, int i2,int i1, int i0);
    说明:使用4个int(32bits)变量来设置__m128i变量;
    返回值:如果返回值__m128i,分为r0,r1,r2,r3返回值规则如下:

r0 := i0
r1 := i1
r2 := i2
r3 := i3

  1. __m128i _mm_cvtps_epi32 (__m128 a)
    Converts packed 32-bit integers in a to packed single-precision (32-bit) floating-point elements.

加载float到__m128

  1. __m128 _mm_set1_ps(float w)
    对应于_mm_load1_ps的功能,不需要字节对齐,需要多条指令。(r0 = r1 = r2 = r3 = w)
  2. __m128 _mm_cvtepi32_ps (__m128i a)
    Converts packed 32-bit integers in a to packed single-precision (32-bit) floating-point elements.

float乘法

__m128 dst = _mm_mul_ps (__m128 a, __m128 b)
将a, b中的32位浮点数相乘,结果打包给dst

取最小值

__m128i _mm_min_epi32 (__m128i a, __m128i b)
Compare packed signed 32-bit integers in a and b, and store packed minimum values in dst.
Operation
FOR j := 0 to 3
i := j*32
dst[i+31:i] := MIN(a[i+31:i], b[i+31:i])
ENDFOR

所以代码修改为

	int* srcX = new int[nZoomDataHeight];int* srcY = new int[nZoomDataWidth];calculateSrcIndex(srcX, nZoomDataHeight, fXZoom , m_nDataHeight - 1);calculateSrcIndex(srcY, nZoomDataWidth, fYZoom, m_nDataWidth - 1);for (size_t row = 0; row < nZoomDataHeight; row++){int remian = nZoomDataWidth % 4;for (size_t column = 0; column < nZoomDataWidth - remian; column += 4){//第一个坐标int srcPos = srcX[row] * m_nDataHeight + srcY[column];int desPos = row * nZoomDataHeight + column;dataZoom[desPos] = m_pData[srcPos];...}}

然后把坐标的计算转为sse

void zoomBlock::zoomDataSSE128(unsigned char* dataZoom, float  fXZoom, float fYZoom)
{int nZoomDataWidth = fXZoom * m_nDataWidth;int nZoomDataHeight = fYZoom * m_nDataHeight;int* srcX = new int[nZoomDataWidth];int* srcY = new int[nZoomDataHeight];calculateSrcIndex(srcX, nZoomDataWidth, fXZoom, m_nDataWidth - 1);calculateSrcIndex(srcY, nZoomDataHeight, fYZoom, m_nDataHeight - 1);for (size_t y = 0; y < nZoomDataHeight; y++){int remian = nZoomDataWidth % 4;for (size_t x = 0; x < nZoomDataWidth - remian; x += 4){__m128i mmsrcX = _mm_set_epi32(srcX[x + 3], srcX[x + 2], srcX[x+1], srcX[x]);__m128i srcPosIndices = _mm_add_epi32(_mm_set1_epi32(srcY[y] * m_nDataWidth),mmsrcX);__m128i desPosIndices = _mm_add_epi32(_mm_set1_epi32(y * nZoomDataWidth),_mm_set_epi32(x + 3, x + 2, x + 1, x));dataZoom[desPosIndices.m128i_i32[0]] = m_pData[srcPosIndices.m128i_i32[0]];dataZoom[desPosIndices.m128i_i32[1]] = m_pData[srcPosIndices.m128i_i32[1]];dataZoom[desPosIndices.m128i_i32[2]] = m_pData[srcPosIndices.m128i_i32[2]];dataZoom[desPosIndices.m128i_i32[3]] = m_pData[srcPosIndices.m128i_i32[3]];/*cout << "srcPosIndices: " << srcPosIndices.m128i_i32[0] << " , desPosIndices : " << desPosIndices.m128i_i32[0] << endl;cout << "srcPosIndices: " << srcPosIndices.m128i_i32[1] << " , desPosIndices : " << desPosIndices.m128i_i32[1] << endl;cout << "srcPosIndices: " << srcPosIndices.m128i_i32[2] << " , desPosIndices : " << desPosIndices.m128i_i32[2] << endl;cout << "srcPosIndices: " << srcPosIndices.m128i_i32[3] << " , desPosIndices : " << desPosIndices.m128i_i32[3] << endl;*/}// Process the remaining elements (if any) without SSEfor (size_t x = nZoomDataWidth - remian; x < nZoomDataWidth; x++){int srcy = std::min(int(y / fYZoom), m_nDataHeight - 1);int srcx = std::min(int(x / fXZoom), m_nDataWidth - 1);int srcPos = srcy * m_nDataHeight + srcx;int desPos = y * nZoomDataHeight + x;dataZoom[desPos] = m_pData[srcPos];}}delete[] srcX;delete[] srcY;
}

完整的代码

 #pragma once
class zoomBlock
{
public:zoomBlock() {};~zoomBlock();void zoomDataSSE128(unsigned char* dataZoom, float  fXZoom, float fYZoom);void zoomData(unsigned char* dataZoom, float  fXZoom, float fYZoom);void test(float  fXZoom =0.5, float fYZoom=0.5);void init(int DataWidth, int DataHeight);
private:inline void calculateSrcIndex(int* srcValues, int size, float zoom, int max);private:unsigned char* m_pData = nullptr;float m_fXZoom = 1 ;//x轴缩放比例  m_nXZoom=1时 不缩放float m_fYZoom = 1 ;//y轴缩放比例int m_nDataWidth = 0;int m_nDataHeight = 0;
};#include "zoomBlock.h"
#include <stdio.h>
#include <iostream>
#include<iomanip>
#include<immintrin.h> 
using namespace std;
#define SAFE_DELETE_ARRAY(p) { if( (p) != NULL ) delete[] (p); (p) = NULL; }zoomBlock::~zoomBlock()
{SAFE_DELETE_ARRAY(m_pData);
}
void zoomBlock::init(int DataWidth, int DataHeight)
{m_nDataWidth = DataWidth;m_nDataHeight = DataHeight;m_pData = new unsigned char[m_nDataWidth* m_nDataHeight];for (int i = 0; i < m_nDataWidth * m_nDataHeight; ++i){m_pData[i] = static_cast<unsigned char>(i);  // Replace this with your data initialization logic}
}void zoomBlock::zoomData(unsigned char* dataZoom, float  fXZoom, float fYZoom)
{int nZoomDataWidth = fXZoom * m_nDataWidth;int nZoomDataHeight = fYZoom * m_nDataHeight;for (size_t y = 0; y < nZoomDataHeight; y++){for (size_t x = 0; x < nZoomDataWidth; x ++){//1int srcy = std::min(int(y / fYZoom), m_nDataHeight - 1);int srcx = std::min(int(x / fXZoom), m_nDataWidth - 1);//2int srcPos = srcy * m_nDataWidth + srcx;int desPos = y * nZoomDataWidth + x;dataZoom[desPos] = m_pData[srcPos];}}
}inline void zoomBlock::calculateSrcIndex(int* srcValues, int size, float zoom,int max)
{__m128i mmIndex, mmSrcValue, mmMax;mmMax = _mm_set1_epi32(max);float zoomReciprocal = 1.0f / zoom;int remian = size % 4;for (size_t i = 0; i < size - remian; i += 4){mmIndex = _mm_set_epi32(i + 3, i + 2, i + 1, i);mmSrcValue = _mm_cvttps_epi32(_mm_mul_ps(_mm_cvtepi32_ps(mmIndex), _mm_set1_ps(zoomReciprocal)));// Ensure srcValues are within the valid range [0, max]mmSrcValue = _mm_min_epi32(mmSrcValue, mmMax);// Store the result to the srcValues array_mm_storeu_si128(reinterpret_cast<__m128i*>(&srcValues[i]), mmSrcValue);}// Process the remaining elements (if any) without SSEfor (size_t i = size - remian; i < size; i++){srcValues[i] = std::min(int(i / zoom), max);}
}void zoomBlock::zoomDataSSE128(unsigned char* dataZoom, float  fXZoom, float fYZoom)
{int nZoomDataWidth = fXZoom * m_nDataWidth;int nZoomDataHeight = fYZoom * m_nDataHeight;int* srcX = new int[nZoomDataWidth];int* srcY = new int[nZoomDataHeight];calculateSrcIndex(srcX, nZoomDataWidth, fXZoom, m_nDataWidth - 1);calculateSrcIndex(srcY, nZoomDataHeight, fYZoom, m_nDataHeight - 1);for (size_t y = 0; y < nZoomDataHeight; y++){int remian = nZoomDataWidth % 4;for (size_t x = 0; x < nZoomDataWidth - remian; x += 4){/*int srcPos = srcx * m_nDataHeight + srcy;int desPos = row * nZoomDataHeight + column;*///dataZoom[desPos] = m_pData[srcPos];//__m128i mmsrcY = _mm_loadu_si128((__m128i*)(srcY));__m128i mmsrcX = _mm_set_epi32(srcX[x + 3], srcX[x + 2], srcX[x+1], srcX[x]);__m128i srcPosIndices = _mm_add_epi32(_mm_set1_epi32(srcY[y] * m_nDataWidth),mmsrcX);__m128i desPosIndices = _mm_add_epi32(_mm_set1_epi32(y * nZoomDataWidth),_mm_set_epi32(x + 3, x + 2, x + 1, x));dataZoom[desPosIndices.m128i_i32[0]] = m_pData[srcPosIndices.m128i_i32[0]];dataZoom[desPosIndices.m128i_i32[1]] = m_pData[srcPosIndices.m128i_i32[1]];dataZoom[desPosIndices.m128i_i32[2]] = m_pData[srcPosIndices.m128i_i32[2]];dataZoom[desPosIndices.m128i_i32[3]] = m_pData[srcPosIndices.m128i_i32[3]];/*cout << "srcPosIndices: " << srcPosIndices.m128i_i32[0] << " , desPosIndices : " << desPosIndices.m128i_i32[0] << endl;cout << "srcPosIndices: " << srcPosIndices.m128i_i32[1] << " , desPosIndices : " << desPosIndices.m128i_i32[1] << endl;cout << "srcPosIndices: " << srcPosIndices.m128i_i32[2] << " , desPosIndices : " << desPosIndices.m128i_i32[2] << endl;cout << "srcPosIndices: " << srcPosIndices.m128i_i32[3] << " , desPosIndices : " << desPosIndices.m128i_i32[3] << endl;*/}// Process the remaining elements (if any) without SSEfor (size_t x = nZoomDataWidth - remian; x < nZoomDataWidth; x++){int srcy = std::min(int(y / fYZoom), m_nDataHeight - 1);int srcx = std::min(int(x / fXZoom), m_nDataWidth - 1);int srcPos = srcy * m_nDataHeight + srcx;int desPos = y * nZoomDataHeight + x;dataZoom[desPos] = m_pData[srcPos];}}delete[] srcX;delete[] srcY;
}void zoomBlock::test(float  fXZoom, float fYZoom)
{init(8,4);std::cout << "Values in m_pData:" << std::endl;for (int i = 0; i < m_nDataWidth * m_nDataHeight; ++i){std::cout << std::setw(4) << static_cast<int>(m_pData[i]) << " ";if ((i + 1) % m_nDataWidth == 0) {  // Adjust the value based on your datastd::cout << std::endl;}}int nZoomDataWidth = fXZoom * m_nDataWidth;int nZoomDataHeight = fYZoom * m_nDataHeight;unsigned char* dataZoom = new unsigned char[nZoomDataWidth * nZoomDataHeight];zoomDataSSE128(dataZoom, fXZoom, fYZoom);//zoomData(dataZoom, fXZoom, fYZoom);// Print or inspect the values in m_dataZoomstd::cout << "Values in m_dataZoom:" << std::endl;for (int i = 0; i < nZoomDataHeight * nZoomDataWidth; ++i){std::cout << std::setw(4)<< static_cast<int>(dataZoom[i]) << " ";if ((i + 1) % nZoomDataWidth == 0) {  // Adjust the value based on your datastd::cout << std::endl;}}SAFE_DELETE_ARRAY(dataZoom);}int main()
{zoomBlock zoomBlocktest;zoomBlocktest.test(2,1);return 0;
}

在这里插入图片描述

AVX 256

inline void zoomBlock::calculateSrcIndex256(int* srcValues, int size, float zoom, int max)
{__m256i ymmIndex, ymmSrcValue, ymmMax;ymmMax = _mm256_set1_epi32(max);float zoomReciprocal = 1.0f / zoom;int remian = size % 8;for (size_t i = 0; i < size - remian; i += 8){ymmIndex = _mm256_set_epi32(i + 7, i + 6, i + 5, i + 4, i + 3, i + 2, i + 1, i);ymmSrcValue = _mm256_cvtps_epi32(_mm256_mul_ps(_mm256_cvtepi32_ps(ymmIndex), _mm256_set1_ps(zoomReciprocal)));// Ensure srcValues are within the valid range [0, max]ymmSrcValue = _mm256_min_epi32(ymmSrcValue, ymmMax);// Store the result to the srcValues array_mm256_storeu_si256(reinterpret_cast<__m256i*>(&srcValues[i]), ymmSrcValue);}// Process the remaining elements (if any) without AVX2for (size_t i = size - remian; i < size; i++){srcValues[i] = std::min(int(i / zoom), max);}
}
void zoomBlock::zoomDataAVX2(unsigned char* dataZoom, float fXZoom, float fYZoom)
{int nZoomDataWidth = fXZoom * m_nDataWidth;int nZoomDataHeight = fYZoom * m_nDataHeight;int* srcX = new int[nZoomDataWidth];int* srcY = new int[nZoomDataHeight];calculateSrcIndex(srcX, nZoomDataWidth, fXZoom, m_nDataWidth - 1);calculateSrcIndex(srcY, nZoomDataHeight, fYZoom, m_nDataHeight - 1);for (size_t y = 0; y < nZoomDataHeight; y++){int remian = nZoomDataWidth % 8;for (size_t x = 0; x < nZoomDataWidth - remian; x += 8){__m256i ymmSrcX = _mm256_set_epi32(srcX[x + 7], srcX[x + 6], srcX[x + 5], srcX[x + 4],srcX[x + 3], srcX[x + 2], srcX[x + 1], srcX[x]);__m256i srcPosIndices = _mm256_add_epi32(_mm256_set1_epi32(srcY[y] * m_nDataWidth),ymmSrcX);__m256i desPosIndices = _mm256_add_epi32(_mm256_set1_epi32(y * nZoomDataWidth),_mm256_set_epi32(x + 7, x + 6, x + 5, x + 4, x + 3, x + 2, x + 1, x));dataZoom[desPosIndices.m256i_i32[0]] = m_pData[srcPosIndices.m256i_i32[0]];dataZoom[desPosIndices.m256i_i32[1]] = m_pData[srcPosIndices.m256i_i32[1]];dataZoom[desPosIndices.m256i_i32[2]] = m_pData[srcPosIndices.m256i_i32[2]];dataZoom[desPosIndices.m256i_i32[3]] = m_pData[srcPosIndices.m256i_i32[3]];dataZoom[desPosIndices.m256i_i32[4]] = m_pData[srcPosIndices.m256i_i32[4]];dataZoom[desPosIndices.m256i_i32[5]] = m_pData[srcPosIndices.m256i_i32[5]];dataZoom[desPosIndices.m256i_i32[6]] = m_pData[srcPosIndices.m256i_i32[6]];dataZoom[desPosIndices.m256i_i32[7]] = m_pData[srcPosIndices.m256i_i32[7]];}// Process the remaining elements (if any) without AVX2for (size_t x = nZoomDataWidth - remian; x < nZoomDataWidth; x++){int srcy = std::min(int(y / fYZoom), m_nDataHeight - 1);int srcx = std::min(int(x / fXZoom), m_nDataWidth - 1);int srcPos = srcy * m_nDataWidth + srcx;int desPos = y * nZoomDataWidth + x;dataZoom[desPos] = m_pData[srcPos];}}delete[] srcX;delete[] srcY;
}

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

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

相关文章

代理IP以及动态拨号VPS的关系是什么?

在数字时代&#xff0c;网络安全和隐私保护已成为全球关注的热点话题。代理IP和动态拨号VPS作为提升网络匿名性和安全的重要技术&#xff0c;它们在维护网络隐私中扮演着至关重要的角色。虽然这两种技术在表面上看似相似&#xff0c;实际上它们在功能、应用场景以及用户需求满足…

react + antdesign table组件合并行,展开子表格

假如你有这样的一个数据&#xff1a; [{"bigClass":"吃的","smallClass":"水果","item":"苹果"},{"bigClass":"吃的","smallClass":"水果","item":"香蕉…

这些养老难题,只能靠AI来解决了

3 月 5 日刚召开的两会&#xff0c;AI 这个话题妥妥站上了 C 位。不仅政府工作报告首次提出要开展“人工智能”行动&#xff0c;各路科技大佬和人大代表也是围绕着 AI 大模型的技术创新、应用落地和政策法规&#xff0c;展开了热烈积极的建言献策。甚至有互联网大佬建议将人工智…

创建RAID0,RAID5并管理,热备盘,模拟故障

目录 1. RAID介绍以及mdadm安装 1.1 安装mdadm工具 2. 创建raid0 2.1 环境准备 2.2 使用两个磁盘创建RAID0 2.3 查看RAID0信息 2.4 对创建的RAID0进行格式化并挂载 2.5 设置成开机挂载 2.6 删除RAID0 3. 创建raid5 3.1 环境准备 3.2 用3个磁盘来模拟R…

ERC20学习

ERC20简介 ERC20是一种代币标准&#xff0c;用于创建可替代的代币。 ERC20是在以太坊网络上实现的代币标准&#xff0c;它为数字资产或代币定义了一套规则和接口。这些符合ERC20标准的代币在性质上是完全相同的。即每一个代币都可以被另一个同类型的代币替代&#xff0c;这种属…

社区店选址评估的关键指标:确保商业成功的重要因素

对于想开实体店或创业的人来说&#xff0c;选址是决定商业成功的关键因素之一。作为一名开鲜奶吧5年的创业者&#xff0c;我在网上持续分享开店的干货和见解。 在这篇文章中&#xff0c;我将详细介绍社区店选址评估的关键指标&#xff0c;帮助你确保商业成功。 1、人流量&…

2.DOM-事件基础(注册事件、tab栏切换)(案例:注册、轮播图)

案例 注册事件 <!-- //disabled默认情况用户不能点击 --><input type"button" value"我已阅读用户协议(5)" disabled><script>// 分析&#xff1a;// 1.修改标签中的文字内容// 2.定时器// 3.修改标签的disabled属性// 4.清除定时器// …

如何在Windows上使用Docker,搭建一款实用的个人IT工具箱It- Tools

文章目录 1. 使用Docker本地部署it-tools2. 本地访问it-tools3. 安装cpolar内网穿透4. 固定it-tools公网地址 本篇文章将介绍如何在Windows上使用Docker本地部署IT- Tools&#xff0c;并且同样可以结合cpolar实现公网访问。 在前一篇文章中我们讲解了如何在Linux中使用Docker搭…

设计模式(十):抽象工厂模式(创建型模式)

Abstract Factory&#xff0c;抽象工厂&#xff1a;提供一个创建一系列相关或相互依赖对 象的接口&#xff0c;而无须指定它们的具体类。 之前写过简单工厂和工厂方法模式(创建型模式)&#xff0c;这两种模式比较简单。 简单工厂模式其实不符合开闭原则&#xff0c;即对修改关闭…

[MYSQL]当数据库被攻破如何重新恢复

前情提要&#xff1a;mysql数据库默认密码、默认端口没有改&#xff0c;也没做安全防护&#xff0c;导致被攻破被索要比特币。 那我们自然是不能给他们的&#xff0c;下面罗列我的补救方法。 密码修改相关 第一步大家自然都会想到先去修改密码&#xff1a; mysqladmin -u roo…

光谱下的养殖业:数据可视化的现代变革

在数字化时代&#xff0c;数据可视化在养殖业中崭露头角&#xff0c;为这一传统行业注入了新的活力。无论是家禽养殖还是水产养殖&#xff0c;数据可视化都以其直观、高效的特点&#xff0c;为养殖业带来了全新的发展机遇。下面我就以可视化从业者的角度&#xff0c;简单聊聊这…

腾讯云轻量 2核2G4M新用户首购活动,99续费同价来了!!

阿里云199一年续费同价&#xff0c;腾讯云99一年续费同价&#xff0c;平台卷起来&#xff0c;对用户的角度来说&#xff0c;真的是香麻了~ 腾讯云新春采购节&#xff0c;2核2G4兆的基础配置&#xff0c;新官方直接放大招&#xff0c;99一年&#xff0c;活动期间内&#xff0c;…

OpenAI (ChatGPT)中国免费试用地址

GitHub - click33/chatgpt---mirror-station-summary: 汇总所有 chatgpt 镜像站&#xff0c;免费、付费、多模态、国内外大模型汇总等等 持续更新中…… 个人能力有限&#xff0c;搜集到的不多&#xff0c;求大家多多贡献啊&#xff01;众人拾柴火焰高&#xff01;汇总所有 cha…

202104 CSP认证 | DHCP服务器

3. DHCP服务器 我天呢经历了带配额的文件系统我真的极其挫败&#xff0c;然后开始写的时候觉得这个题感觉怎么有点简单…然后就觉得肯定是自己有很多东西没有想到&#xff0c;而且写的时候破罐子破摔觉得肯定会超时… 结果一写&#xff01;哦买噶居然满分了&#xff01; 脑子不…

【探索Linux】—— 强大的命令行工具 P.26(网络编程套接字基本概念—— socket编程接口 | socket编程接口相关函数详细介绍 )

阅读导航 引言一、socket 常见API表二、函数详细介绍01. socket()02. bind()03. listen()04. accept()05. connect()06. send()07. recv()08. close()09. select()10. getaddrinfo()11. sendto()12. recvfrom()13. setsockopt()14. getsockopt()15. shutdown()16. inet_pton()1…

【SpringBoot】多环境切换的灵活配置

文章目录 profile 的使用激活 profile 的方式命令行启动idea 中配置配置文件中激活 开发中最灵活的多环境配置创建四个配置主配置文件其他几个环境配置使用方式 配置文件拆分总结 在日常的开发中&#xff0c;一般都会分好几种环境&#xff0c;比如通常的 开发环境&#xff1a;一…

EXSI create datastore

文章目录 1. 简介2. 清空磁盘3. 删除表4. 创建database 1. 简介 在 ESXi 环境中创建数据存储(Datastore)的步骤如下: 登录 vSphere Web Client 打开 Web 浏览器,输入 ESXi 主机或 vCenter Server 的 IP 地址,使用有权限的账户登录。 在 ESXi 环境中创建数据存储(Datastore)…

Linux 关于NTP同步硬件时钟的可靠性验证

Linux关于NTP同步硬件时钟的可靠性验证 1. 常见的时钟类型1.1 系统时钟1.2 硬件时钟 2. 常见时钟同步方式2.1 ntpd服务2.1.1 推荐配置/etc/ntp.conf2.1.2 推荐配置/etc/sysconfig/ntpd 2.2 定时任务ntpdate2.3 ntp命令同步状态相关命令解读2.3.1 ntpq -pn解读2.3.2 ntpdate -u解…

SpringCloud Ribbon 负载均衡服务调用

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第三篇&#xff0c;即介绍 Ribbon 负载均衡服务调用 二、概述 2.1 Ribbon 是什么 Spring Cloud Ribbon…

OpenCV学习笔记(三)——对于图片的基本操作

目录 读取图片和显示图片 显示图片的大小 将图像设置为灰度图 将图片重新写回指定的地址 显示图片的尺寸 获取图片的类型 读取图片和显示图片 在OpenCV使用cv2.imread()来读取图片&#xff0c;例如&#xff0c;在D盘的Photo的文件夹中有一张图片名称为1的jpeg的图片&am…