完整指南:CNStream流处理多路并发框架适配到NVIDIA Jetson Orin (四) 运行、调试、各种问题解决

news2024/11/10 6:07:03

目录

1 调试jetson-mpeg视频解码模块

1.1 修改config.json

1.2 Picture size 0x0 is invalid

1.3 Process(): Send package failed. Maximum number of attempts reached

1.4 Picture size 2239821608x65535 is invalid

1.5 保存h264文件解码之后的测试图片

1.6 保存RTSP视频解码之后的测试图片

2 调试cv-cuda图片处理模块

2.1 NVCV_ERROR_NOT_IMPLEMENTED: Batch image format must not have subsampled planes, 

2.2 保存NVConvertFormat之后的图片

 参考文献:


记录下将CNStream流处理多路并发Pipeline框架适配到NVIDIA Jetson AGX Orin的过程,以及过程中遇到的问题,我的jetson盒子是用jetpack5.1.3重新刷机之后的,这是系列博客的第四篇,前三篇链接如下:

完整指南:CNStream流处理多路并发框架适配到NVIDIA Jetson Orin (一) 依赖库编译、第三方库编译安装-CSDN博客

完整指南:CNStream流处理多路并发框架适配到NVIDIA Jetson Orin (二) 源码架构流程梳理、代码编写-CSDN博客

完整指南:CNStream流处理多路并发框架适配到NVIDIA Jetson Orin (三) 代码编译、各种问题解决、代码修改-CSDN博客

这篇博客记录下程序运行过程中遇到的错误、以及调试解决各种错误的过程。

1 调试jetson-mpeg视频解码模块

1.1 修改config.json

先把config.json修改成最简单的方式,只保留解码模块

{
  "profiler_config" : {
    "enable_profiling" : false,
    "enable_tracing" : false
  },

  "subgraph:decode" : {
    "config_path" : "configs/decode_config.json"
  },
  
  "subgraph:business" : {
    "config_path" : "configs/business.json"
  }
  
  

}

然后开始运行、调试,

1.2 Picture size 0x0 is invalid

I0909 17:30:40.658268 943351 data_handler_file.cpp:304] [TACLStream SOURCE INFO] [FileHandlerImpl] OnParserInfo(): [5g3223522224262]: Got video info.
I0909 17:30:40.658645 943351 decode_impl_nv.cpp:45] [InferServer] [DecodeFFmpeg] Create(): Use codec type: h264_nvmpi
[h264_nvmpi @ 0xffff100035f0] [IMGUTILS @ 0xffff34fc4770] Picture size 0x0 is invalid
[h264_nvmpi @ 0xffff100035f0] video_get_buffer: image parameters invalid
[h264_nvmpi @ 0xffff100035f0] get_buffer() failed
[h264_nvmpi @ 0xffff100035f0] [IMGUTILS @ 0xffff34fc4770] Picture size 0x0 is invalid
[h264_nvmpi @ 0xffff100035f0] video_get_buffer: image parameters invalid
[h264_nvmpi @ 0xffff100035f0] get_buffer() failed
E0909 17:30:40.659263 943351 decode_impl_nv.cpp:67] [InferServer] [DecodeFFmpeg] Failed to open codec
E0909 17:30:40.660058 943351 decode.cpp:64] [InferServer] [DecodeService] Create(): Create decoder failed
E0909 17:30:40.660167 943351 video_decoder.cpp:88] [TACLStream SOURCE ERROR] [5g3223522224262]: Create decoder failed
E0909 17:30:40.660254 943351 data_handler_file.cpp:315] [TACLStream SOURCE ERROR] [FileHandlerImpl] OnParserInfo(): Create decoder failed, ret = 0
E0909 17:30:40.660997 943351 data_handler_file.cpp:220] [TACLStream SOURCE ERROR] [FileHandlerImpl] Loop(): [5g3223522224262]: PrepareResources failed.
W0909 17:30:40.661371 941831 task_session_mgr.cpp:855] [TACLStream SESSION_MGR WARN] [TNVPipeline] received stream error from stream: 5g3223522224262, remove it from pipeline.

在ffmpeg的源码中搜了下这个报错,

看了下代码,应该是宽高没设置的问题,但是我找了半天这个ff_get_buffer是怎么被avcodec_open2函数调用的,没找到,于是我直接吧nvmpi和ffmepg这两个库都编译成debug版本然后调试。

首先把jetson-ffmpeg编译成debug版本,修改其中的cmake那一行

git clone https://github.com/Keylost/jetson-ffmpeg.git
cd jetson-ffmpeg
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug ..
make
sudo make install
sudo ldconfig

然后把ffmpeg编译一个debug版本,修改其中的config那一行

./configure --enable-static --enable-shared --enable-nvmpi --enable-debug=3 --disable-optimizations
git clone git://source.ffmpeg.org/ffmpeg.git -b release/4.4 --depth=1
cd ffmpeg
cp /data/chw/jetson-ffmpeg/ffmpeg_patches/ffmpeg4.4_nvmpi.patch /data/chw/ffmpeg/ffmpeg_nvmpi.patch
git apply ffmpeg_nvmpi.patch
./configure --enable-static --enable-shared --enable-nvmpi
make -j8
make install
ldconfig

然后调试看,找到了调用关系

然后报错是因为这里的宽高没给他赋值,判断是0就会报错。

另外,在查找这个bug的过程中发现,ffmpeg里面还有个问题就是数据格式如果传NV12那么里面也会报错提示不支持,所以这里还需要修改ffmpeg内部的源码,重新编译库,

另外,我的解码代码加上这几行

        codec_context_->pix_fmt = AV_PIX_FMT_NV12;
        codec_context_->width = create_params_.max_width;
        codec_context_->height = create_params_.max_height;

1.3 Process(): Send package failed. Maximum number of attempts reached

这个错误我检查了代码也没发现错误呀,调试也没调试出来啥,然后我看了下我的视频文件是用的一个mp4文件,我换成一个.h264视频文件就没有这个错误了。

1.4 Picture size 2239821608x65535 is invalid

[h264_nvmpi @ 0xffff00000e30] [IMGUTILS @ 0xffff26affa60] Picture size 2239821608x65535 is invalid
[h264_nvmpi @ 0xffff00000e30] [IMGUTILS @ 0xffff26affa10] Picture size 0x0 is invalid
[h264_nvmpi @ 0xffff00000e30] video_get_buffer: image parameters invalid
[h264_nvmpi @ 0xffff00000e30] get_buffer() failed
E0910 17:38:43.887912 1224545 decode_impl_nv.cpp:70] [InferServer] [DecodeFFmpeg] Failed to open codec
E0910 17:38:43.890803 1224545 decode.cpp:64] [InferServer] [DecodeService] Create(): Create decoder failed
E0910 17:38:43.891697 1224545 video_decoder.cpp:88] [TACLStream SOURCE ERROR] [5g3223522224262]: Create decoder failed
E0910 17:38:43.891896 1224545 data_handler_rtsp.cpp:515] [TACLStream SOURCE ERROR] [RtspHandlerImpl] DecodeLoop(): Create decoder failed.

我把mp4文件换成RTSP,报错

我调试进去看了下是因为宽高没被赋值。然后我调试到处理RTSP流的地方,发现

其实这里是有获取这两个值的代码的,并且我调试看到也有值,只不过这两行代码之前被注释掉了,放开注释。

然后重新编译、运行,刚才的报错消失。

1.5 保存h264文件解码之后的测试图片

在这里增加测试代码,直接用opencv保存图片

    void DecodeFFmpeg::OnFrame(AVFrame *av_frame, uint32_t frame_id) {

        static int debug_count  = 0;
        cv::Mat yuv_mat(av_frame_->height * 3 / 2, av_frame_->width, CV_8UC1, av_frame_->data[0]);//调试代码,记得修改。
        cv::Mat bgr_mat;
        cv::cvtColor(yuv_mat, bgr_mat, cv::COLOR_YUV2BGR_NV12); //调试代码,记得修改,这是原代码  
        debug_count =  debug_count + 1;
        char decode_name[20] = {};

        if((debug_count < 3000) && (debug_count % 2 == 0))
        {
            sprintf(decode_name, "OnDecodeFrame_%d.jpg",  debug_count);
            cv::imwrite(decode_name, bgr_mat);
        }

        BufSurface *surf{};
        if (create_params_.GetBufSurf(&surf, av_frame_->width, av_frame->height, BUF_COLOR_FORMAT_BGR,
            create_params_.surf_timeout_ms, create_params_.userdata) < 0) {
            LOG(ERROR) << "[InferServer] [DecoderAcl] OnFrame(): Get BufSurface failed";
            OnError(-1);
            return;}
        if (surf->mem_type != BUF_MEMORY_MANAGED) {
            LOG(ERROR) << "[InferServer] [DecoderAcl] OnFrame(): BufSurface memory type must be BUF_MEMORY_MANAGED";
            return;
        }

发现图片保存不正常,

好吧,

我写代码直接保存yuv文件

    void DecodeFFmpeg::SaveYUVFrame(AVFrame *av_frame, const char *filename) {
        FILE *file = fopen(filename, "wb");
        if (!file) {
            fprintf(stderr, "Could not open %s for writing\n", filename);
            return;
        }

        // 写入 Y 分量
        for (int i = 0; i < av_frame->height; i++) {
            fwrite(av_frame->data[0] + i * av_frame->linesize[0], 1, av_frame->width, file);
        }

        // 写入交错的 UV 分量
        for (int i = 0; i < av_frame->height / 2; i++) {
            fwrite(av_frame->data[1] + i * av_frame->linesize[1], 1, av_frame->width, file);
        }

        // // 写入 U 分量
        // for (int i = 0; i < av_frame->height / 2; i++) {
        //     fwrite(av_frame->data[1] + i * av_frame->linesize[1], 1, av_frame->width / 2, file);
        // }

        // // 写入 V 分量
        // for (int i = 0; i < av_frame->height / 2; i++) {
        //     fwrite(av_frame->data[1] + (av_frame->height / 2)*av_frame->linesize[1] + i * av_frame->linesize[1], 1, av_frame->width / 2, file);
        // }

        fclose(file);
    }

然后

    void DecodeFFmpeg::OnFrame(AVFrame *av_frame, uint32_t frame_id) {

        static int debug_count  = 0;
        cv::Mat yuv_mat(av_frame_->height * 3 / 2, av_frame_->width, CV_8UC1, av_frame_->data[0]);//调试代码,记得修改。
        cv::Mat bgr_mat;
        cv::cvtColor(yuv_mat, bgr_mat, cv::COLOR_YUV2BGR_NV12); //调试代码,记得修改,这是原代码  
        debug_count =  debug_count + 1;
        char decode_name[20] = {};


        // 保存 YUV 数据
        if (debug_count < 3000 && debug_count % 2 == 0) {
            char yuv_filename[20];
            sprintf(yuv_filename, "frame_%d.yuv", debug_count);
            SaveYUVFrame(av_frame, yuv_filename);
        }

        if((debug_count < 3000) && (debug_count % 2 == 0))
        {
            
            sprintf(decode_name, "OnDecodeFrame_%d.jpg",  debug_count);
            cv::imwrite(decode_name, bgr_mat);
        }

yuv文件打开正常。 

那么就是我的yuv转BGR的代码有问题了,

我把代码改成下面这种

    void DecodeFFmpeg::OnFrame(AVFrame *av_frame, uint32_t frame_id) {

        static int debug_count  = 0;
        //cv::Mat yuv_mat(av_frame_->height * 3 / 2, av_frame_->width, CV_8UC1, av_frame_->data[0]);//调试代码,记得修改。
        cv::Mat yuv_mat(av_frame_->height * 3 / 2, av_frame_->width, CV_8UC1);//调试代码,记得修改。
        // 拷贝 Y 分量数据
        memcpy(yuv_mat.data, av_frame->data[0], av_frame->height * av_frame->linesize[0]);

        // 拷贝 UV 分量数据
        memcpy(yuv_mat.data + av_frame->height * av_frame->linesize[0], av_frame->data[1], av_frame->height / 2 * av_frame->linesize[1]);
        cv::Mat bgr_mat;
        cv::cvtColor(yuv_mat, bgr_mat, cv::COLOR_YUV2BGR_NV12); //调试代码,记得修改,这是原代码  
        debug_count =  debug_count + 1;
        char decode_name[20] = {};


        // 保存 YUV 数据
        if (debug_count < 3000 && debug_count % 2 == 0) {
            char yuv_filename[20];
            sprintf(yuv_filename, "frame_%d.yuv", debug_count);
            SaveYUVFrame(av_frame, yuv_filename);
        }

        if((debug_count < 3000) && (debug_count % 2 == 0))
        {
            
            sprintf(decode_name, "OnDecodeFrame_%d.jpg",  debug_count);
            cv::imwrite(decode_name, bgr_mat);
        }

跟之前的区别在与我先创建一个mat,然后我memcpy分别从data[0]和data[1]拷贝两次,这样保存的图片正常,那么问题出在哪里。我觉得在于av_frame_->data[0]是Y分量,av_frame_->data[1]是UV分量,但是av_frame_->data[0]和av_frame_->data[1]之间并不是连续的,我用计算器验证一下,这个是av_frame_->data[0]和av_frame_->data[1]的差。

这个是1920*1080的值。 

1.6 保存RTSP视频解码之后的测试图片

 解码RTSP视频流,保存图片正常。

2 调试cv-cuda图片处理模块

2.1 NVCV_ERROR_NOT_IMPLEMENTED: Batch image format must not have subsampled planes, 

运行报错

terminate called after throwing an instance of 'nvcv::Exception'
  what():  NVCV_ERROR_NOT_IMPLEMENTED: Batch image format must not have subsampled planes, but it is: NVCV_IMAGE_FORMAT_NV12
Aborted (core dumped)

直接问下必应

修改代码,将

nvcv::Tensor::Requirements in_reqs = nvcv::Tensor::CalcRequirements(1, { buf_surf.width_stride, buf_surf.height }, CastColorFmt(buf_surf.color_format));

修改成下面的代码,也就是按照FMT_U8给yuv申请tensor。

        if (buf_surf.color_format == BUF_COLOR_FORMAT_NV12 || buf_surf.color_format == BUF_COLOR_FORMAT_NV21) {
            in_reqs = nvcv::Tensor::CalcRequirements(1, { buf_surf.width, buf_surf.height * 3 / 2 }, nvcv::FMT_U8);
        }
        else {
            in_reqs = nvcv::Tensor::CalcRequirements(1, { buf_surf.width, buf_surf.height }, CastColorFmt(buf_surf.color_format));
        }

2.2 保存NVConvertFormat之后的图片

我在这个函数最后面增加测试代码,保存测试图片


    int TransformerNV::NVConvertFormat(BufSurface *src, BufSurface *dst, TransformParams *transform_params) {
        auto& src_surf = src->surface_list[0];
        auto& dst_surf = dst->surface_list[0];

        auto src_tensor = GetTensorFromBufSurf(src_surf);
        auto dst_tensor = GetTensorFromBufSurf(dst_surf);

        NVCVColorConversionCode cvt_code{ NVCV_COLOR_YUV2BGR_NV12 };
        switch (src_surf.color_format) {
        case BUF_COLOR_FORMAT_NV12:
        {
            if (dst_surf.color_format == BUF_COLOR_FORMAT_BGR) {
                cvt_code = NVCV_COLOR_YUV2BGR_NV12;
            }
        }break;
        case BUF_COLOR_FORMAT_BGR:
        {
            if (dst_surf.color_format == BUF_COLOR_FORMAT_NV12) {
                cvt_code = NVCV_COLOR_BGR2YUV_NV12;
            }
        }break;
        case BUF_COLOR_FORMAT_RGB:
        {
            if (dst_surf.color_format == BUF_COLOR_FORMAT_NV12) {
                cvt_code = NVCV_COLOR_RGB2YUV_NV12;
            }
        }break;
        default:
            cvt_code = NVCV_COLOR_YUV2BGR_NV12;
        }

        if ((src_surf.color_format == BUF_COLOR_FORMAT_NV12 || src_surf.color_format == BUF_COLOR_FORMAT_NV21)
            && (dst_surf.color_format == BUF_COLOR_FORMAT_BGR || dst_surf.color_format == BUF_COLOR_FORMAT_RGB)) {
            cvt_code = NVCV_COLOR_YUV2BGR_NV12;
        }
        else if ((src_surf.color_format == BUF_COLOR_FORMAT_NV12 || src_surf.color_format == BUF_COLOR_FORMAT_NV21)
                 && (dst_surf.color_format == BUF_COLOR_FORMAT_BGR || dst_surf.color_format == BUF_COLOR_FORMAT_RGB)) {
            cvt_code = NVCV_COLOR_YUV2BGR_NV12;
        }

        (*cvtcolor_op_)(reinterpret_cast<cudaStream_t>(cu_stream_), src_tensor, dst_tensor, cvt_code);
        CUDA_SAFECALL(cuStreamSynchronize(cu_stream_)
                      , "[InferServer] [TransformerNV] NVConvertFormat failed.", -1);
 
        // Assuming 'dst_tensor' holds the converted BGR data.
        cv::Mat bgr_image(dst_surf.height, dst_surf.width, CV_8UC3, dst->surface_list[0].data_ptr);
        cv::imwrite("output_image.jpg", bgr_image);


        return 0;
    }

结果如下,

我知道是什么原因,这是因为前面解码的时候,解码结束之后赋值内存的时候用的是av_frame_->data,问题原因就和上面保存解码测试图片一样的。

 参考文献:

在NVIDIA Jetson AGX Orin中使用jetson-ffmpeg调用硬件编解码加速处理-CSDN博客

NVIDIA Jetson AGX Orin源码编译安装CV-CUDA-CSDN博客

GitHub - Cambricon/CNStream: CNStream is a streaming framework for building Cambricon machine learning pipelines http://forum.cambricon.com https://gitee.com/SolutionSDK/CNStream

easydk/samples/simple_demo/common/video_decoder.cpp at master · Cambricon/easydk · GitHub

aclStream流处理多路并发Pipeline框架中 视频解码 代码调用流程整理、类的层次关系整理、回调函数赋值和调用流程整理-CSDN博客

aclStream流处理多路并发Pipeline框架中VEncode Module代码调用流程整理、类的层次关系整理、回调函数赋值和调用流程整理-CSDN博客

FFmpeg/doc/examples at master · FFmpeg/FFmpeg · GitHub

GitHub - CVCUDA/CV-CUDA: CV-CUDA™ is an open-source, GPU accelerated library for cloud-scale image processing and computer vision.

如何使用FFmpeg的解码器—FFmpeg API教程 · FFmpeg原理

C++ API — CV-CUDA Beta documentation (cvcuda.github.io)

CV-CUDA/tests/cvcuda/system at main · CVCUDA/CV-CUDA · GitHub

Resize — CV-CUDA Beta documentation

CUDA Runtime API :: CUDA Toolkit Documentation

CUDA Toolkit Documentation 12.6 Update 1

完整指南:CNStream流处理多路并发框架适配到NVIDIA Jetson Orin (一) 依赖库编译、第三方库编译安装-CSDN博客

完整指南:CNStream流处理多路并发框架适配到NVIDIA Jetson Orin (二) 源码架构流程梳理、代码编写-CSDN博客

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

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

相关文章

跨境电商热卖季:选品攻略与实战指南

下半年是跨境电商的旺季 促销节点接踵而至。从感恩节、万圣节、到黑色星期五、网络星期一&#xff0c;再到圣诞节、新年促销等&#xff0c;这些节日不仅激发了消费者的购买欲望&#xff0c;也为跨境电商卖家提供了巨大的市场机遇。那么在这些有望实现销量飞跃的黄金时期&#x…

【SLAM】稀疏矩阵的乘法优化小结

1. 思路小结 要优化你提供的稀疏矩阵乘法代码&#xff0c;我们可以引入CSR&#xff08;压缩稀疏行&#xff09;格式来避免遍历零元素&#xff0c;从而提高效率。CSR格式通过仅存储非零元素以及它们的行和列索引&#xff0c;可以有效减少稀疏矩阵计算时的时间复杂度。下面是对代…

讲解GPU 训练大模型步骤

GPU在训练大模型的工作过程中&#xff0c;扮演着至关重要的角色&#xff0c;其强大的并行计算能力能够显著提升训练速度和效率。以下是GPU训练大模型的详细步骤&#xff1a; 选择合适的GPU和云平台 1. 考虑计算能力 计算能力需求&#xff1a;大模型训练通常需要强大的计算能…

Qt实现登录界面

本文基于Qt实现一个简单的登录界面&#xff0c;主要使用到Widget、button、edit等控件&#xff0c;基于自定义的信号槽实现界面的跳转&#xff0c;使用绘图设备添加背景图等。 1. 创建主界面 设计主界面的样式&#xff0c;并添加相关的控件。如下显示&#xff1a; 代码如下&…

搜索功能技术方案

1. 背景与需求分析 门户平台需要实现对服务信息的高效查询&#xff0c;包括通过关键字搜索服务以及基于地理位置进行服务搜索。面对未来可能的数据增长和性能需求&#xff0c;选择使用 Elasticsearch 来替代 MySQL 的全文检索功能。这一选择的背景与需求可以总结为以下几点&am…

对标世界一流!望繁信科技受邀参加2023企业财务数智化转型论坛

2023年7月21日&#xff0c;由中国CFO发展中心联合浙江省总会计师协会、南京审计大学会计学院、安徽财经大学会计学院举办的“2023企业财务数智化转型论坛&#xff08;长三角站&#xff09;”在上海隆重举办。论坛现场座无虚席&#xff0c;全天候、多维度的话题探讨为广大CFO呈现…

[WEBPWN]BaseCTF week1 题解(新手友好教程版)

WEB A Dark Room 这道题的考点是查看网页源代码 网页源代码这里看到的是网页的html css js在用户浏览器上执行的代码 有时候很多铭感信息&#xff0c;或者关键信息。 查看网页源代码的几种方式 1 右键点击查看网页源代码 2 F12 3 Ctrl U 快捷键 HTTP是什么 HTTP&#x…

车路云一体化系统中的数据交互内容

车路云与相关支撑平台的数据交互是构建智能交通系统的重要组成部分&#xff0c;它涉及到车辆、道路基础设施&#xff08;路侧单元RSU&#xff09;与云端平台及其相关支撑平台之间的复杂信息流通与协同工作。以下是对这一过程的详细解析&#xff1a; 一、数据交互的组成部分 车…

DMDRS学习

DMDRS学习 产品介绍 达梦数据复制软件&#xff08;简称DMDRS&#xff09;是一种用于同构数据库、异构数据库以及各种数据管理系统之间的数据复制软件。DMDRS采用模块化的设计&#xff0c;通过灵活配置不同的功能模块&#xff0c;实现多功能的数据复制服务&#xff0c;以满足多…

Java虚拟机 - 实战篇

一、内存调优 1. 什么是内存泄漏 &#xff08;1&#xff09;内存溢出和内存泄漏 2. 监控Java内存的常用工具 &#xff08;1&#xff09;Top命令 &#xff08;2&#xff09;VisualVM &#xff08;3&#xff09;Arthas &#xff08;4&#xff09;Prometheus Grafana &#xff…

人工智能--模型评估指标

背景 1、分类回归模型的评估指标 分类模型的目标是将输入数据分配到一个离散类别中&#xff0c;常见的评估指标如下&#xff1a; 准确率 (Accuracy) 解释&#xff1a;表示模型预测正确的样本占总样本的比例。适用于类分布平衡的情况&#xff0c;但在类别不平衡时表现不佳。…

十张图“拿捏”MySQL中B+树的生成过程

hello&#xff0c;我是大都督周瑜&#xff0c;这篇文章带你用十张图“拿捏”MySQL中B树的生成过程。 更多干货技术文章、面试题&#xff0c;欢迎关注我的公众号&#xff1a;IT周瑜 当MySQL接收到一条以下SQL时&#xff0c;表示要从t1表中查询数据&#xff1a; select * from t…

基于java+springboot+vue实现的林业产品推荐系统(文末源码+Lw)135

基于SpringBootVue的实现的林业产品推荐系统&#xff08;源码数据库万字Lun文流程图ER图结构图演示视频软件包&#xff09; 系统功能&#xff1a; 林业产品推荐系统是在MySQL中建立数据表保存信息&#xff0c;运用SpringBoot框架和Java语言编写。 并按照软件设计开发流程进行…

新书宣传:《量子安全:信息保护新纪元》

《量子安全&#xff1a;信息保护新纪元》 前言本书的看点本书的目录结语 前言 你好&#xff01; 这是我第一次发布类广告的博文&#xff0c;目的也很单纯&#xff0c;希望以作者的身份介绍一下自己出版的图书——《量子安全&#xff1a;信息保护新纪元》。此书于2024年7月出版…

【go】pprof 性能分析

前言 go pprof是 Go 语言提供的性能分析工具。它可以帮助开发者分析 Go 程序的性能问题&#xff0c;包括 CPU 使用情况、内存分配情况、阻塞情况等。 主要功能 CPU 性能分析 go pprof可以对程序的 CPU 使用情况进行分析。它通过在一定时间内对程序的执行进行采样&#xff0…

17个常见的电子邮件营销错误及避免方法

我们都在邮件营销中犯过错误。你点击发送&#xff0c;然后感到一阵沉重的感觉。你搞砸了&#xff0c;现在全世界都能看到你的错误。这就像把一封信放在瓶子里扔进无边的互联网海洋&#xff0c;你无法把它收回来。 有些邮件营销错误显而易见&#xff0c;可能会让你所有的努力化…

Redis学习Day3——项目工程开发`

扩展阅读推荐&#xff1a; 黑马程序员Redis入门到实战教程_哔哩哔哩_bilibili 使用git命令行将本地仓库代码上传到gitee/github远程仓库-CSDN博客 一、项目介绍及其初始化 学习Redis的过程&#xff0c;我们还将遇到各种实际问题&#xff0c;例如缓存击穿、雪崩、热Key等问题&…

想将桌面移动到D盘,但是不小心将D盘整个改成桌面的快捷方式了的解决办法

本帖为经验分享&#xff0c;因而附带了解释。 着急的uu请直接按照红色&#xff08;蓝色&#xff09;加粗标号直接操作&#xff01; 目录 一、问题描述 二、问题出现的原因 三、解决方法 一、问题描述 想将桌面移动到D盘&#xff0c;但是不小心将D盘整个改成桌面的快捷方式。…

老旧电力系统安全隐患增加 该如何预防电气线路老化等因素引发的电气火灾呢?

为应对我国电气火灾事故频发的挑战&#xff0c;安科瑞电气股份有限公司开发了AcrelCloud-6000安全用电管理云平台。这一平台依托移动互联网和云计算技术&#xff0c;结合物联网传感器&#xff0c;将办公楼、学校、医院、工厂、体育场馆、宾馆及福利院等人员密集场所的电气安全数…

爬虫--基于python的旅游网站数据分析与可视化实现---附源码78517

摘要 在数字化时代&#xff0c;旅游网站积累了大量用户数据&#xff0c;这些数据中蕴藏着丰富的信息和价值。为了更好地理解用户行为、优化旅游服务体验和提高业务运营效率&#xff0c;对旅游网站数据进行深度挖掘和可视化展示显得尤为重要。本文借助Python编程语言&#xff0c…