【OpenVINO™】在 MacOS 上使用 OpenVINO™ C# API 部署 Yolov5

来源:https://www.cnblogs.com/guojin-blogs/p/18009621
-Advertisement-
Play Games

YOLOv5 是革命性的 "單階段"對象檢測模型的第五次迭代,旨在實時提供高速、高精度的結果,是世界上最受歡迎的視覺人工智慧模型,代表了Ultralytics對未來視覺人工智慧方法的開源研究,融合了數千小時研發中積累的經驗教訓和最佳實踐。同時官方發佈的模型已經支持 OpenVINO™ 部署工具加速模... ...


在 MacOS 上使用 OpenVINO™ C# API 部署 Yolov5
項目介紹

YOLOv5 是革命性的 "單階段"對象檢測模型的第五次迭代,旨在實時提供高速、高精度的結果,是世界上最受歡迎的視覺人工智慧模型,代表了Ultralytics對未來視覺人工智慧方法的開源研究,融合了數千小時研發中積累的經驗教訓和最佳實踐。同時官方發佈的模型已經支持 OpenVINO™ 部署工具加速模型推理,因此在該項目中,我們將結合之前開發的 OpenVINO™ C# API 部署 YOLOv5 DET 模型實現物體對象檢測。

項目鏈接為:

https://github.com/guojin-yan/OpenVINO-CSharp-API

項目源碼鏈接為:

https://github.com/guojin-yan/OpenVINO-CSharp-API-Samples/tree/master/model_samples/yolov5/yolov5_det_opencvsharp
https://github.com/guojin-yan/OpenVINO-CSharp-API-Samples/tree/master/model_samples/yolov5/yolov5_det_emgucv

目錄

1. 前言

1.1 OpenVINO™ C# API

英特爾發行版 OpenVINO™ 工具套件基於 oneAPI 而開發,可以加快高性能電腦視覺和深度學習視覺應用開發速度工具套件,適用於從邊緣到雲的各種英特爾平臺上,幫助用戶更快地將更準確的真實世界結果部署到生產系統中。通過簡化的開發工作流程,OpenVINO™ 可賦能開發者在現實世界中部署高性能應用程式和演算法。

OpenVINO™ 2023.2 於 2023 年 11 月 16 日發佈,該工具包帶來了挖掘生成人工智慧全部潛力的新功能。更多的生成式 AI 覆蓋和框架集成,以最大限度地減少代碼更改,並且擴展了對直接 PyTorch 模型轉換的模型支持。支持更多新的模型,包括 LLaVA、chatGLM、Bark 和 LCM 等著名模型。支持更廣泛的大型語言模型(LLM)和更多模型壓縮技術,支持運行時推理支持以下 Int4 模型壓縮格式,通過神經網路壓縮框架(NNCF) 進行本機 Int4 壓縮等一系列新的功能。

OpenVINO™ C# API 是一個 OpenVINO™ 的 .Net wrapper,應用最新的 OpenVINO™ 庫開發,通過 OpenVINO™ C API 實現 .Net 對 OpenVINO™ Runtime 調用,使用習慣與 OpenVINO™ C++ API 一致。OpenVINO™ C# API 由於是基於 OpenVINO™ 開發,所支持的平臺與 OpenVINO™ 完全一致,具體信息可以參考 OpenVINO™。通過使用 OpenVINO™ C# API,可以在 .NET、.NET Framework等框架下使用 C# 語言實現深度學習模型在指定平臺推理加速。

1.2 YOLOv5

​ YOLOv5 是革命性的 "單階段"對象檢測模型的第五次迭代,旨在實時提供高速、高精度的結果,是世界上最受歡迎的視覺人工智慧模型,代表了Ultralytics對未來視覺人工智慧方法的開源研究,融合了數千小時研發中積累的經驗教訓和最佳實踐。

2. 模型下載與轉換

2.1 環境安裝

首先創建Yolov5模型下載與轉換環境,此處為了更好的管理環境,使用Anaconda創建一個虛擬環境用於安裝Yolov5模型下載與轉換環境,首先使用conda創建一個虛擬環境,在命令行中依次輸入以下指令:

conda create -n yolo python=3.10
conda activate yolo

接下來安裝Yolov5模型下載與轉換環境,基礎的Yolov5模型下載需要通過克隆官方源碼實現,在命令行中依次輸入以下指令實現環境的安裝與配置即可:

git clone https://github.com/ultralytics/yolov5
cd yolov5
pip install -r requirements.txt
pip install --upgrade openvino-nightly

2.2 Yolov5 模型下載

Yolov5 官方提供了模型導出與轉換的方式,用戶只需要調用該介面便可以,在命令行中輸入以下指令便可以直接導出Yolov5模型:

cd yolov5
python export.py --weights yolov5s.pt --include onnx

結果輸出如下圖所示:

使用Netron工具打開模型文件,查看模型結構,如下圖所示:

官方預訓練模型是在COCO數據集上訓練的,因此導出的模型可以識別80種物體。模型輸入節點為images,輸入為歸一化後的圖像數據,其輸入大小為640×640;模型的輸出節點為output0,輸出大小為25200×85,其中25200(640÷8=80,640÷16=40,640÷32=20,3×80×80+3×40×40+3×20×20=25200)表示識別結果個數,85表示[cx, cy, w, h, confidence, score0, ···,score79],分別為識別框信息、識別結果中最大置信度以及80中類別結果的分數。

2.3 轉換IR模型

接下來直接使用 OpenVINO™ 工具直接進行模型轉換,在CMD中輸入以下指令即可:

ovc yolov5s.onnx

3. Yolov5 DET 項目配置(OpenCvSharp版)

3.1 項目創建

如果開發者第一次在MacOS系統上使用C#編程語言,可以參考《在MacOS系統上配置OpenVINO™ C# API》文章進行配置。

首先使用dotnet創建一個測試項目,在終端中輸入一下指令:

dotnet new console --framework net6.0 --use-program-main -o yolov5-det 

3.2 添加項目依賴

MacOS系統目前主要分為兩類,一類是使用intel處理器的X64位的系統,一類是使用M系列晶元的arm64位系統,目前OpenVINO官方針對這兩種系統都提供了編譯後的系統,所以目前OpenVINO.CSharp.API針對這兩種系統都提供了支持。

此處以M系列處理器的MacOS平臺為例安裝項目依賴,首先是安裝OpenVINO™ C# API項目依賴,在命令行中輸入以下指令即可:

dotnet add package OpenVINO.CSharp.API
dotnet add package OpenVINO.runtime.macos-arm64
dotnet add package OpenVINO.CSharp.API.Extensions
dotnet add package OpenVINO.CSharp.API.Extensions.OpenCvSharp

關於在MacOS上搭建 OpenVINO™ C# API 開發環境請參考以下文章: 在MacOS上搭建OpenVINO™C#開發環境

接下來安裝使用到的圖像處理庫 OpenCvSharp,在命令行中輸入以下指令即可:

dotnet add package OpenCvSharp4
dotnet add package OpenCvSharp4.Extensions
dotnet add package OpenCvSharp4.runtime.osx_arm64 --prerelease

關於在MacOS上搭建 OpenCvSharp 開發環境請參考以下文章: 【OpenCV】在MacOS上使用OpenCvSharp

添加完成項目依賴後,項目的配置文件如下所示:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <RootNamespace>yolov5_det</RootNamespace>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="OpenCvSharp4" Version="4.9.0.20240103" />
    <PackageReference Include="OpenCvSharp4.Extensions" Version="4.9.0.20240103" />
    <PackageReference Include="OpenCvSharp4.runtime.osx_arm64" Version="4.8.1-rc" />
    <PackageReference Include="OpenVINO.CSharp.API" Version="2023.2.0.4" />
    <PackageReference Include="OpenVINO.CSharp.API.Extensions" Version="1.0.1" />
    <PackageReference Include="OpenVINO.CSharp.API.Extensions.OpenCvSharp" Version="1.0.4" />
    <PackageReference Include="OpenVINO.runtime.macos-arm64" Version="2023.3.0.1" />
  </ItemGroup>

</Project>

3.3 定義預測方法

(1) 使用常規方式部署模型

Yolov5 屬於比較經典單階段目標檢測模型,其模型輸入為640*640的歸一化處理後的圖像數據,輸出為未進行NMS的推理結果,因此在獲取推理結果後,需要進行NMS,其實現代碼如下所示:

static void yolov5_det(string model_path, string image_path, string device)
{
    // -------- Step 1. Initialize OpenVINO Runtime Core --------
    Core core = new Core();
    // -------- Step 2. Read inference model --------
    Model model = core.read_model(model_path);
    OvExtensions.printf_model_info(model);
    // -------- Step 3. Loading a model to the device --------
    start = DateTime.Now;
    CompiledModel compiled_model = core.compile_model(model, device);
    // -------- Step 4. Create an infer request --------
    InferRequest infer_request = compiled_model.create_infer_request();
    // -------- Step 5. Process input images --------
    Mat image = new Mat(image_path); // Read image by opencvsharp
    int max_image_length = image.Cols > image.Rows ? image.Cols : image.Rows;
    Mat max_image = Mat.Zeros(new OpenCvSharp.Size(max_image_length, max_image_length), MatType.CV_8UC3);
    Rect roi = new Rect(0, 0, image.Cols, image.Rows);
    image.CopyTo(new Mat(max_image, roi));
    float factor = (float)(max_image_length / 640.0);
    // -------- Step 6. Set up input data --------
    Tensor input_tensor = infer_request.get_input_tensor();
    Shape input_shape = input_tensor.get_shape();
    Mat input_mat = CvDnn.BlobFromImage(max_image, 1.0 / 255.0, new OpenCvSharp.Size(input_shape[2], input_shape[3]), 0, true, false);
    float[] input_data = new float[input_shape[1] * input_shape[2] * input_shape[3]];
    Marshal.Copy(input_mat.Ptr(0), input_data, 0, input_data.Length);
    input_tensor.set_data<float>(input_data);
    // -------- Step 7. Do inference synchronously --------
    infer_request.infer();
    // -------- Step 8. Get infer result data --------
    Tensor output_tensor = infer_request.get_output_tensor();
    int output_length = (int)output_tensor.get_size();
    float[] output_data = output_tensor.get_data<float>(output_length);

    // -------- Step 9. Process reault  --------
    Mat result_data = new Mat(25200, 85, MatType.CV_32F, output_data);
    // Storage results list
    List<Rect> position_boxes = new List<Rect>();
    List<int> class_ids = new List<int>();
    List<float> confidences = new List<float>();
    // Preprocessing output results
    for (int i = 0; i < result_data.Rows; i++)
    {
        float confidence = result_data.At<float>(i, 4);
        if (confidence < 0.5)
        {
            continue;
        }
        Mat classes_scores = new Mat(result_data, new Rect(5, i, 80, 1));
        OpenCvSharp.Point max_classId_point, min_classId_point;
        double max_score, min_score;
        // Obtain the maximum value and its position in a set of data
        Cv2.MinMaxLoc(classes_scores, out min_score, out max_score,
            out min_classId_point, out max_classId_point);
        // Confidence level between 0 ~ 1
        // Obtain identification box information
        if (max_score > 0.25)
        {
            float cx = result_data.At<float>(i, 0);
            float cy = result_data.At<float>(i, 1);
            float ow = result_data.At<float>(i, 2);
            float oh = result_data.At<float>(i, 3);
            int x = (int)((cx - 0.5 * ow) * factor);
            int y = (int)((cy - 0.5 * oh) * factor);
            int width = (int)(ow * factor);
            int height = (int)(oh * factor);
            Rect box = new Rect();
            box.X = x;
            box.Y = y;
            box.Width = width;
            box.Height = height;

            position_boxes.Add(box);
            class_ids.Add(max_classId_point.X);
            confidences.Add((float)confidence);
        }
    }
    // NMS non maximum suppression
    int[] indexes = new int[position_boxes.Count];
    CvDnn.NMSBoxes(position_boxes, confidences, 0.5f, 0.5f, out indexes);
    for (int i = 0; i < indexes.Length; i++)
    {
        int index = indexes[i];
        Cv2.Rectangle(image, position_boxes[index], new Scalar(0, 0, 255), 2, LineTypes.Link8);
        Cv2.Rectangle(image, new OpenCvSharp.Point(position_boxes[index].TopLeft.X, position_boxes[index].TopLeft.Y + 30),
            new OpenCvSharp.Point(position_boxes[index].BottomRight.X, position_boxes[index].TopLeft.Y), new Scalar(0, 255, 255), -1);
        Cv2.PutText(image, class_ids[index] + "-" + confidences[index].ToString("0.00"),
            new OpenCvSharp.Point(position_boxes[index].X, position_boxes[index].Y + 25),
            HersheyFonts.HersheySimplex, 0.8, new Scalar(0, 0, 0), 2);
    }
    string output_path = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(image_path)),
        Path.GetFileNameWithoutExtension(image_path) + "_result.jpg");
    Cv2.ImWrite(output_path, image);
    Slog.INFO("The result save to " + output_path);
    Cv2.ImShow("Result", image);
    Cv2.WaitKey(0);
}

(2) 使用模型結構處理處理數據

目前 OpenVINO™ 已經支持在模型結構中增加數據的前後處理流程,並且在 OpenVINO™ C# API 中也已經實現了該功能介面,所以在此處演示瞭如何將模型輸入數據處理流程封裝到模型中,通過 OpenVINO™ 進行數據處理的加速處理,如下麵代碼所示:

static void yolov5_det_with_process(string model_path, string image_path, string device)
{
    ······
    // -------- Step 2. Read inference model --------
    start = DateTime.Now;
    Model model = core.read_model(model_path);
    OvExtensions.printf_model_info(model);
    PrePostProcessor processor = new PrePostProcessor(model);
    Tensor input_tensor_pro = new Tensor(new OvType(ElementType.U8), new Shape(1, 640, 640, 3));
    InputInfo input_info = processor.input(0);
    InputTensorInfo input_tensor_info = input_info.tensor();
    input_tensor_info.set_from(input_tensor_pro).set_layout(new Layout("NHWC")).set_color_format(ColorFormat.BGR);
    PreProcessSteps process_steps = input_info.preprocess();
    process_steps.convert_color(ColorFormat.RGB).resize(ResizeAlgorithm.RESIZE_LINEAR)
        .convert_element_type(new OvType(ElementType.F32)).scale(255.0f).convert_layout(new Layout("NCHW"));
    Model new_model = processor.build();
    // -------- Step 3. Loading a model to the device --------
    CompiledModel compiled_model = core.compile_model(new_model, device);
    // -------- Step 4. Create an infer request --------
    InferRequest infer_request = compiled_model.create_infer_request();
    // -------- Step 5. Process input images --------
    Mat image = new Mat(image_path); // Read image by opencvsharp
    int max_image_length = image.Cols > image.Rows ? image.Cols : image.Rows;
    Mat max_image = Mat.Zeros(new OpenCvSharp.Size(max_image_length, max_image_length), MatType.CV_8UC3);
    Rect roi = new Rect(0, 0, image.Cols, image.Rows);
    image.CopyTo(new Mat(max_image, roi));
    Cv2.Resize(max_image, max_image, new OpenCvSharp.Size(640, 640));
    float factor = (float)(max_image_length / 640.0);
    // -------- Step 6. Set up input data --------
    Tensor input_tensor = infer_request.get_input_tensor();
    Shape input_shape = input_tensor.get_shape();
    byte[] input_data = new byte[input_shape[1] * input_shape[2] * input_shape[3]];
    Marshal.Copy(max_image.Ptr(0), input_data, 0, input_data.Length);
    IntPtr destination = input_tensor.data();
    Marshal.Copy(input_data, 0, destination, input_data.Length);
    // -------- Step 7. Do inference synchronously --------
    ······
}

由於目前還沒有完全實現所有的 OpenVINO™ 的預處理介面,因此只能實現部分預處理過程封裝到模型中,此處主要是做了以下處理:

  • 數據類型轉換:byte->float
  • 數據維度轉換:NHWC->NCHW
  • 圖像色彩空間轉換:BGR->RGB
  • 數據歸一化處理:[0,1]->[0,255]

因此將一些數據處理流程封裝到模型中後,在進行模型推理時,只需要將讀取到的圖片數據Resize為640*640後,就可以直接將數據載入到模型即可。

(3) 使用 OpenVINO™ C# API 封裝的介面

YOLOv5 是當前工業領域十分流行的目標檢測模型,因此在封裝 OpenVINO™ C# API 時,提供了快速部署 Yolov5 模型的介面,實現代碼如下所示:

static void yolov5_det_using_extensions(string model_path, string image_path, string device)
{
    Yolov5DetConfig config = new Yolov5DetConfig();
    config.set_model(model_path);
    Yolov5Det yolov8 = new Yolov5Det(config);
    Mat image = Cv2.ImRead(image_path);
    DetResult result = yolov8.predict(image);
    Mat result_im = Visualize.draw_det_result(result, image);
    Cv2.ImShow("Result", result_im);
    Cv2.WaitKey(0);
}

3.4 預測方法調用

定義好上述方法後,便可以直接在主函數中調用該方法,只需要在主函數中增加以下代碼即可:

yolov5_det("yolov5s.xml", "test_image.png", "AUTO");
yolov5_det_with_process("yolov5s.xml", "test_image.png", "AUTO");
yolov5_det_using_extensions("yolov5s.xml", "test_image.png", "AUTO");

如果開發者自己沒有進行模型下載與轉換,又同時想快速體驗該項目,我此處提供了線上的轉換後的模型以及帶預測圖片,開發者可以直接在主函數中增加以下代碼,便可以直接自動下載模型以及推理數據,並調用推理方法,實現程式直接運行。

static void Main(string[] args)
{
    string model_path = "";
    string image_path = "";
    string device = "AUTO";
    if (args.Length == 0)
    {
        if (!Directory.Exists("./model"))
        {
            Directory.CreateDirectory("./model");
        }
        if (!File.Exists("./model/yolov5s.bin") && !File.Exists("./model/yolov5s.bin"))
        {
            if (!File.Exists("./model/yolov5s.tar"))
            {
                _ = Download.download_file_async("https://github.com/guojin-yan/OpenVINO-CSharp-API-Samples/releases/download/Model/yolov5s.tar",
                    "./model/yolov5s.tar").Result;
            }
            Download.unzip("./model/yolov585s.tar", "./model/");
        }

        if (!File.Exists("./model/test_image.jpg"))
        {
            _ = Download.download_file_async("https://github.com/guojin-yan/OpenVINO-CSharp-API-Samples/releases/download/Image/test_det_02.jpg",
                "./model/test_image.jpg").Result;
        }
        model_path = "./model/yolov5s.xml";
        image_path = "./model/test_image.jpg";
    }
    else if (args.Length >= 2)
    {
        model_path = args[0];
        image_path = args[1];
        device = args[2];
    }
    else
    {
        Console.WriteLine("Please enter the correct command parameters, for example:");
        Console.WriteLine("> 1. dotnet run");
        Console.WriteLine("> 2. dotnet run <model path> <image path> <device name>");
    }
    // -------- Get OpenVINO runtime version --------

    OpenVinoSharp.Version version = Ov.get_openvino_version();

    Slog.INFO("---- OpenVINO INFO----");
    Slog.INFO("Description : " + version.description);
    Slog.INFO("Build number: " + version.buildNumber);

    Slog.INFO("Predict model files: " + model_path);
    Slog.INFO("Predict image  files: " + image_path);
    Slog.INFO("Inference device: " + device);
    Slog.INFO("Start yolov8 model inference.");

    yolov5_det(model_path, image_path, device);
    //yolov5_det_with_process(model_path, image_path, device);
    //yolov5_det_using_extensions(model_path, image_path, device);
}

為了減少文章篇幅,所以此處只提供了有差異的代碼,如果想獲取完整代碼,請訪問GitHub代碼倉庫,獲取項目源碼,鏈接為:

https://github.com/guojin-yan/OpenVINO-CSharp-API-Samples/tree/master/model_samples/yolov5/yolov5_det_opencvsharp

4. Yolov5 DET 項目配置(Emgu.CV 版)

同樣地,為了滿足Emgu.CV開發者的需求,此處同樣地提供了Emgu.CV版本的Yolov5的模型部署代碼以及使用流程,此處為了簡化文章內容,對於和上文重覆的步驟不在進行展開講述。

4.1 添加項目依賴

首先是安裝OpenVINO™ C# API項目依賴,在命令行中輸入以下指令即可:

dotnet add package OpenVINO.CSharp.API
dotnet add package OpenVINO.runtime.macos-arm64
dotnet add package OpenVINO.CSharp.API.Extensions
dotnet add package OpenVINO.CSharp.API.Extensions.EmguCV

接下來安裝使用到的圖像處理庫 Emgu.CV,在命令行中輸入以下指令即可:

dotnet add package Emgu.CV
dotnet add package Emgu.CV.runtime.mini.macos

關於在MacOS上搭建 OpenCvSharp 開發環境請參考以下文章: 【OpenCV】在MacOS上使用Emgu.CV

添加完成項目依賴後,項目的配置文件如下所示:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <RootNamespace>yolov5_det</RootNamespace>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Emgu.CV" Version="4.8.1.5350" />
    <PackageReference Include="Emgu.CV.runtime.mini.macos" Version="4.8.1.5350" />
    <PackageReference Include="OpenVINO.CSharp.API" Version="2023.2.0.4" />
    <PackageReference Include="OpenVINO.CSharp.API.Extensions" Version="1.0.1" />
    <PackageReference Include="OpenVINO.CSharp.API.Extensions.EmguCV" Version="1.0.4.1" />
    <PackageReference Include="OpenVINO.runtime.macos-arm64" Version="2023.3.0.1" />
  </ItemGroup>

</Project>

4.2 定義預測方法

模型部署流程與上一節中使用OpenCvSharp的基本一致,主要是替換了圖像處理的工具,同時提供瞭如上一節中所展示的三種部署方式。此處為了減少文章篇幅,此處不在展示詳細的部署代碼,如果想獲取相關代碼,請訪問項目GitHub,下載所有的測試代碼,項目鏈接為:

https://github.com/guojin-yan/OpenVINO-CSharp-API-Samples/tree/master/model_samples/yolov5/yolov5_det_emgucv

5. 項目運行與演示

5.1 項目編譯

接下來輸入項目編譯指令進行項目編譯,輸入以下指令即可:

dotnet build

程式編譯後輸出為:

5.2 項目文件運行

接下來運行編譯後的程式文件,在CMD中輸入以下指令,運行編譯後的項目文件:

dotnet run --no-build

運行後項目輸出為:

6. 總結

在該項目中,我們結合之前開發的 OpenVINO C# API 項目部署YOLOv5模型,成功實現了對象目標檢測,並且根據不同開發者的使用習慣,同時提供了OpenCvSharp以及Emgu.CV兩種版本,供各位開發者使用。最後如果各位開發者在使用中有任何問題,歡迎大家與我聯繫。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 工商銀行和華為雲牽頭,並聯合7家金融機構共同編製的《金融行業開放平臺資料庫轉型白皮書》榮獲2023年度十佳課題。 ...
  • 優秀的程式應該儘可能地規避問題。因此,以後在服務商系統里,當定義包含漢字的欄位時,使用 nvarchar2,而非 varchar2。 因此,在服務商系統作為我司系統的小眾系統的背景下,Oracle的技術特性我們不一一曉知是可以理解和接受的。而如何在不一一曉知這些技術特性的情況下,能夠規避這些技術特性... ...
  • 環境 MySQL 5.7 非GTID模式多線程複製。 現象 某MySQL資料庫從節點因故障宕機(因故障直接宕機,非正常關閉),重啟之後發現複製狀態異常,show slave的結果中Slave_SQL_Running為No,錯誤代碼為1062 error code,從系統表performance_sc ...
  • 一、為什麼要做診斷引擎 毓數平臺是奇富科技公司自主研發的一站式大數據管理、開發、分析平臺,覆蓋大數據資產管理、數據開發及任務調度、自助分析及可視化、統一指標管理等多個數據生命周期流程,讓用戶使用數據的同時,挖掘數據最大的價值。而毓數平臺的大數據任務調度底層是基於Apache DolphinSched ...
  • 作者,祝青平,華為雲資料庫內核高級工程師。擅長資料庫優化器內核研發,9年資料庫內核研發經驗,參與多個TP以及AP資料庫的研發工作。 近日,華為雲資料庫社區下麵有這樣一條用戶提問留言:請問,如何通過MySQL提升DISTINCT,尤其是多表連接下DISTINCT的查詢效率? 在回答這個問題之前,我們先 ...
  • Hello 大家好,先祝福大家新年快樂。 AgileConfig 1.9.0 版本終於趕在農曆年前發佈了。 Mongodb 當前做為一款非常成熟的 Nosql 產品,已經有越來越多的產品或項目基於它來構建。在 AgileConfig 開源的這幾年之間,陸陸續續收到不少同學問為啥不支持 M ...
  • 引言: 在現代互聯網應用程式的開發和部署中,選擇一個可靠、高性能的Web伺服器是至關重要的。Nginx是一個備受推崇的選擇,它以其卓越的性能和可靠性在開發者社區中享有盛譽。本文將介紹Nginx的概念、優勢,以及如何使用Nginx作為Web伺服器和反向代理。 什麼是Nginx? Nginx(發音為“e ...
  • 折騰Docker 有幾天了,整別的都沒這個糟心。目前已經順利部署運行起來了。順便給大家分享下處理在Windows上使用.NET部署到Docker的相關問題解決方法。 1. Docker無法安裝問題 (下圖是網上找了個類似的安裝失敗截圖,頁面大致一樣,就是提示內容是 Docker Desktop 只能 ...
一周排行
    -Advertisement-
    Play Games
  • 在C#中使用SQL Server實現事務的ACID(原子性、一致性、隔離性、持久性)屬性和使用資料庫鎖(悲觀鎖和樂觀鎖)時,你可以通過ADO.NET的SqlConnection和SqlTransaction類來實現。下麵是一些示例和概念說明。 實現ACID事務 ACID屬性是事務處理的四個基本特征, ...
  • 我們在《SqlSugar開發框架》中,Winform界面開發部分往往也用到了自定義的用戶控制項,對應一些特殊的界面或者常用到的一些局部界面內容,我們可以使用自定義的用戶控制項來提高界面的統一性,同時也增強了使用的便利性。如我們Winform界面中用到的分頁控制項、附件顯示內容、以及一些公司、部門、菜單的下... ...
  • 在本篇教程中,我們學習瞭如何在 Taurus.MVC WebMVC 中進行數據綁定操作。我們還學習瞭如何使用 ${屬性名稱} CMS 語法來綁定頁面上的元素與 Model 中的屬性。通過這些步驟,我們成功實現了一個簡單的數據綁定示例。 ...
  • 是在MVVM中用來傳遞消息的一種方式。它是在MVVMLight框架中提供的一個實現了IMessenger介面的類,可以用來在ViewModel之間、ViewModel和View之間傳遞消息。 Send 接受一個泛型參數,表示要發送的消息內容。 Register 方法用於註冊某個對象接收消息。 pub ...
  • 概述:在WPF中,通過EventHandler可實現基礎和高級的UI更新方式。基礎用法涉及在類中定義事件,併在UI中訂閱以執行更新操作。高級用法藉助Dispatcher類,確保在非UI線程上執行操作後,通過UI線程更新界面。這兩種方法提供了靈活而可靠的UI更新機制。 在WPF(Windows Pre ...
  • 概述:本文介紹了在C#程式開發中如何利用自定義擴展方法測量代碼執行時間。通過使用簡單的Action委托,開發者可以輕鬆獲取代碼塊的執行時間,幫助優化性能、驗證演算法效率以及監控系統性能。這種通用方法提供了一種便捷而有效的方式,有助於提高開發效率和代碼質量。 在軟體開發中,瞭解代碼執行時間是優化程式性能 ...
  • 概述:Cron表達式是一種強大的定時任務調度工具,通過配置不同欄位實現靈活的時間規定。在.NET中,Quartz庫提供了簡便的方式配置Cron表達式,實現精準的定時任務調度。這種靈活性和可擴展性使得開發者能夠根據需求輕鬆地制定和管理定時任務,例如每天備份系統日誌或其他重要操作。 Cron表達式詳解 ...
  • 概述:.NET提供多種定時器,如System.Windows.Forms.Timer適用於UI,System.Web.UI.Timer用於Web,System.Diagnostics.Timer用於性能監控,System.Threading.Timer和System.Timers.Timer用於一般 ...
  • 問題背景 有同事聯繫我說,在生產環境上,訪問不了我負責的common服務,然後我去檢查common服務的health endpoint, 沒問題,然後我問了下異常,timeout導致的System.OperationCanceledException。那大概率是客戶端的問題,會不會是埠耗盡,用ne ...
  • 前言: 在本篇 Taurus.MVC WebMVC 入門開發教程的第四篇文章中, 我們將學習如何實現數據列表的綁定,通過使用 List<Model> 來展示多個數據項。 我們將繼續使用 Taurus.Mvc 命名空間,同時探討如何在視圖中綁定並顯示一個 Model 列表。 步驟1:創建 Model ...