基于Linux的云端垃圾分類助手

項目簡介

本項目旨在開發一個基于嵌入式系統的智能垃圾分類裝置。該裝置能夠通過串口通信、語音播報、網絡通信等多種方式,實現垃圾的自動識別和分類投放。系統采用多線程設計,確保各功能模塊高效并行工作。

項目功能

  1. 垃圾分類識別

系統使用攝像頭拍攝垃圾圖片,并將其上傳到阿里云進行分類識別。
識別結果包括干垃圾、濕垃圾、可回收垃圾、有害垃圾等類別。

  1. 語言播報

系統通過串口與語言模塊通信,根據垃圾分類結果進行語音播報。
語音模塊接收指令并播放相應的提示音。

  1. OLED顯示

系統通過OLED屏幕顯示當前垃圾分類結果。

4.垃圾桶蓋控制

系統根據識別結果控制相應垃圾桶的開關。
使用PWM信號控制舵機開關垃圾桶蓋。

5.網絡通信

系統支持通過網絡接收客戶端指令,實現遠程控制。
通過TCP/IP協議接收來自客戶端的“open”指令,觸發垃圾分類操作。

硬件需求

Orange Pi Zero2
攝像頭模塊
語音播報模塊SU-03T
128*64 OLED顯示屏
SG90舵機
串口通信模塊

運行環境

操作系統:Linux
編程語言:C語言、Python

功能實現

garbage.py

調用阿里云SDK API

# -*- coding: utf-8 -*-
# 引入依賴包
# pip install alibabacloud_imagerecog20190930
//引入必要的Python包,包括阿里云圖像識別服務的SDK包。
import os
import io
from urllib.request import urlopen
from alibabacloud_imagerecog20190930.client import Client
from alibabacloud_imagerecog20190930.models import ClassifyingRubbishAdvanceRequest
from alibabacloud_tea_openapi.models import Config
from alibabacloud_tea_util.models import RuntimeOptions//通過讀取環境變量中的AccessKey ID和AccessKey Secret,配置阿里云客戶端的認證信息和訪問域名。
config = Config(# 創建AccessKey ID和AccessKey Secret,請參考https://help.aliyun.com/document_detail/175144.html。# 如果您用的是RAM用戶的AccessKey,還需要為RAM用戶授予權限AliyunVIAPIFullAccess,請參考https://help.aliyun.com/document_detail/145025.html# 從環境變量讀取配置的AccessKey ID和AccessKey Secret。運行代碼示例前必須先配置環境變量。access_key_id=os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_ID'),access_key_secret=os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_SECRET'),# 訪問的域名endpoint='imagerecog.cn-shanghai.aliyuncs.com',# 訪問的域名對應的regionregion_id='cn-shanghai'
)//垃圾分類函數,提供了從本地文件讀取和從URL讀取,兩種方式
def alibaba_garbage():#場景一:文件在本地img = open(r'/tmp/garbage.jpg', 'rb') //打開文件所在路徑#場景二:使用任意可訪問的url#url = 'https://viapi-test-bj.oss-cn-beijing.aliyuncs.com/viapi-3.0domepic/imagerecog/ClassifyingRubbish/ClassifyingRubbish1.jpg'#img = io.BytesIO(urlopen(url).read())classifying_rubbish_request = ClassifyingRubbishAdvanceRequest()classifying_rubbish_request.image_urlobject = imgruntime = RuntimeOptions()try:# 初始化Clientclient = Client(config)//調用阿里云圖像識別服務,將上傳的垃圾圖片進行分類,并返回分類結果。response = client.classifying_rubbish_advance(classifying_rubbish_request, runtime)# 獲取整體結果print(response.body.to_map()['Data']['Elements'][0]['Category'])return response.body.to_map()['Data']['Elements'][0]['Category']except Exception as error:return 'gat failed'在腳本被直接執行時,調用‘alibaba_garbage’函數。
if __name__ == "__main__":alibaba_garbage()

garbage.c

在C語言中嵌入Python解釋器以調用Python函數。

#include <Python.h>
#include "garbage.h"void garbage_init(void)
{	//初始化Python解釋器Py_Initialize();//導入‘sys’模塊PyObject *sys = PyImport_ImportModule("sys");//獲取‘sys.path’模塊PyObject *path = PyObject_GetAttrString(sys, "path");//將當前目錄‘.’添加到'sys.path'中,以便導入當前目錄下的Python腳本。PyList_Append(path, PyUnicode_FromString("."));
}void garbage_final(void)
{//終止Python解釋器。	Py_Finalize();
}char *garbage_category(char *category)
{//導入名為‘garbage.py’的python模塊。//如果導入失敗,打印錯誤信息并跳轉到'FAILED_MODULE'表簽進行清理。PyObject *pModule = PyImport_ImportModule("garbage");if(!pModule){PyErr_Print();printf("ERROR: faild to load garbage.py\n");goto FAILED_MODULE;}//獲取'garbage'模塊中的'alibaba_garbage'函數。//如果獲取失敗或函數不可調用,打印錯誤信息并跳轉到 FAILED_FUNC 標簽進行清理。PyObject *pFunc = PyObject_GetAttrString(pModule, "alibaba_garbage");if(!pFunc || !PyCallable_Check(pFunc)){PyErr_Print();printf("ERROR: function alibaba_garbage not found or not callable\n");goto FAILED_FUNC;}//調用 alibaba_garbage 函數,不傳遞參數。//如果調用失敗,打印錯誤信息并跳轉到 FAILED_VALUE 標簽進行清理。PyObject *pValue = PyObject_CallObject(pFunc, NULL);if(!pValue){PyErr_Print();printf("ERROR: function call failed\n");goto FAILED_VALUE;}char *result = NULL;if(!PyArg_Parse(pValue, "s", &result)){PyErr_Print();printf("ERROR: parse failed\n");goto FAILED_RESULT;}category = (char *)malloc(sizeof(char *)*(strlen(result)+1));memset(category, 0 , (strlen(result)+1));strncpy(category, result, (strlen(result)+1));// 釋放發生錯誤之前分配的內存空間
FAILED_RESULT:Py_DECREF(pValue);
FAILED_VALUE:Py_DECREF(pFunc);
FAILED_FUNC:Py_DECREF(pModule);
FAILED_MODULE:return category;
}

內存泄漏

內存泄漏是指在計算機程序中,動態分配的內存未被正確釋放,導致這些內存塊不能被重新分配和使用。隨著程序的運行,未釋放的內存不斷累積,最終可能耗盡可用內存資源,導致系統性能下降,甚至使程序或系統崩潰。

內存泄漏的成因
  1. 未釋放動態分配的內存:

程序在使用 malloc、calloc 或 realloc 分配內存后,沒有使用 free 函數釋放內存。

  1. 循環或遞歸調用中未釋放內存:

在循環或遞歸調用中,動態分配的內存未被釋放。

  1. 異常退出或提前返回:

程序在處理錯誤或異常時,沒有正確釋放已經分配的內存。

  1. 丟失指針引用:

動態分配的內存地址被覆蓋或丟失,沒有其他指針指向該內存塊。

棧上分配和堆上分配
棧上分配

棧上分配的內存(例如局部變量)在函數調用結束后會自動釋放。

void function() {int local_variable = 10; // 棧上分配// local_variable 在函數結束時自動釋放
}
堆上分配

堆上分配的內存需要程序員手動釋放,否則會導致內存泄漏。

void function() {int *heap_variable = (int *)malloc(sizeof(int) * 10); // 堆上分配// 使用完 heap_variable 后需要手動釋放內存free(heap_variable);
}

garbage.h

#ifndef __GARBAGE__H
#define __GARBAGE__Hvoid garbage_init(void);
void garbage_final(void);
char *garbage_category(char *category);//宏定義拍照指令和圖片地址
#define WGET_CMD "wget http://127.0.0.1:8080/?action=snapshot -O /tmp/garbage.jpg"
#define GARBAGE_FILE "/tmp/garbage.jpg"#endif

main.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <wiringPi.h>
#include <pthread.h>#include "uartTool.h"
#include "garbage.h"
#include "pwm.h"
#include "myoled.h"
#include "socket.h"int serial_fd = -1;
pthread_cond_t cond;
pthread_mutex_t mutex;//該函數通過執行 shell 命令 ps 檢測特定進程是否正在運行。
static int detect_process(const char *process_name)
{int n = -1;FILE *strm;char buf[128] = {0};sprintf(buf, "ps -ax | grep %s | grep -v grep", process_name);if ((strm = popen(buf, "r")) != NULL) {if (fgets(buf, sizeof(buf), strm) != NULL) {n = atoi(buf);}}else{return -1;}pclose(strm);return n;
}//從串口讀取語音命令,并根據特定條件觸發條件變量信號。
void *pget_voice(void *arg)
{unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0x55, 0xAA};int len = 0;if (-1 == serial_fd) {printf("%s|%s|%d: open serial failed\n", __FILE__, __func__, __LINE__);pthread_exit(0);}printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);while(1){len = serialGetstring(serial_fd, buffer);if (len > 0 && buffer[2] == 0x46) {pthread_mutex_lock(&mutex);buffer[2] = 0x00;pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);}}pthread_exit(0);
}//發送語音命令到串口。
void *psend_voice(void *arg)
{pthread_detach(pthread_self());unsigned char *buffer = (unsigned char *)arg;if (-1 == serial_fd){printf("%s|%s|%d: open serial failed\n", __FILE__, __func__, __LINE__);pthread_exit(0);}if (NULL != buffer){serialSendstring(serial_fd, buffer, 6);}pthread_exit(0);
}//控制垃圾桶打開和關閉。
void *popen_trash_can(void *arg)
{pthread_detach(pthread_self());unsigned char *buffer = (unsigned char *)arg;if (buffer[2] == 0x43) {printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__, buffer[2]);pwm_write(PWM_RECOVERABLE_GARBAGE);delay(2000);pwm_stop(PWM_RECOVERABLE_GARBAGE);}else if (buffer[2] != 0x45){printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__, buffer[2]);pwm_write(PWM_GARBAGE);delay(2000);pwm_stop(PWM_GARBAGE);}pthread_exit(0);
}//初始化 OLED 顯示屏并顯示垃圾分類結果。
void*poled_show(void *arg)
{pthread_detach(pthread_self());myoled_init();oled_show(arg);pthread_exit(0);
}//等待條件變量信號,執行垃圾分類邏輯,并觸發語音、垃圾桶和 OLED 顯示。
void *pcategory(void *arg)
{unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0x55, 0xAA};char *category = NULL;pthread_t send_voice_tid, trash_tid, oled_tid;while(1){pthread_mutex_lock(&mutex);pthread_cond_wait(&cond, &mutex);pthread_mutex_unlock(&mutex);buffer[2] = 0x00;system(WGET_CMD);if (0 == access(GARBAGE_FILE, F_OK)){category = garbage_category(category);if (strstr(category, "干垃圾")){buffer[2] = 0x41;}else if (strstr(category, "濕垃圾")){buffer[2] = 0x42;}else if (strstr(category, "可回收垃圾")){buffer[2] = 0x43;}else if (strstr(category, "有害垃圾")){buffer[2] = 0x44;}else {buffer[2] = 0x45;}}else{buffer[2] = 0x45;}//開語音播報線程pthread_create(&trash_tid, NULL, psend_voice, (void *)buffer);//開垃圾桶開關pthread_create(&send_voice_tid, NULL, popen_trash_can, (void *)buffer);//oled顯示線程pthread_create(&oled_tid, NULL, poled_show, (void *)buffer);remove(GARBAGE_FILE);}}void *pget_socket(void *arg)
{int s_fd = -1;// 服務器套接字文件描述符int c_fd = -1;// 客戶端套接字文件描述符char buffer[6];// 接收數據緩沖區int nread = -1;// 接收到的數據長度struct sockaddr_in c_addr;// 客戶端地址結構memset(&c_addr,0,sizeof(struct sockaddr_in));// 初始化客戶端地址結構s_fd = socket_init(IPADDR, IPPORT);// 初始化服務器套接字printf("%s|%s|%d:s_fd=%d\n", __FILE__, __func__, __LINE__, s_fd);if (-1 == s_fd){pthread_exit(0);}sleep(3);int clen = sizeof(struct sockaddr_in);// 客戶端地址結構的長度while(1){c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);// 接受客戶端連接int keepalive = 1; // 開啟TCP KeepAlive功能int keepidle = 5; // 5s內沒收到數據開始發送心跳包int keepcnt = 3; // 每次發送心跳包的次數int keepintvl = 3; // 每3s發送一次心跳包setsockopt(c_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive, sizeof(keepalive));setsockopt(c_fd, SOL_TCP, TCP_KEEPIDLE, (void *) &keepidle, sizeof(keepidle));setsockopt(c_fd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcnt, sizeof(keepcnt));setsockopt(c_fd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepintvl, sizeof(keepintvl));        printf("%s|%s|%d: Accept a connection from %s:%d\n", __FILE__, __func__, __LINE__, inet_ntoa(c_addr.sin_addr), ntohs(c_addr.sin_port));if(c_fd == -1){perror("accept");continue;}while(1){memset(buffer, 0, sizeof(buffer));nread = recv(c_fd, buffer, sizeof(buffer), 0); //n_read = read(c_fd,buffer, sizeof(buffer));printf("%s|%s|%d:nread=%d, buffer=%s\n", __FILE__, __func__,__LINE__, nread, buffer);if (nread > 0){if (strstr(buffer, "open")){pthread_mutex_lock(&mutex);pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);}}else if(0 == nread || -1 == nread){break;}}close(c_fd);}pthread_exit(0);
}int main(int argc, char *argv[])
{   int len = 0;int ret = -1;char *category = NULL;pthread_t get_voice_tid, category_tid, get_socket_tid;wiringPiSetup();garbage_init();ret = detect_process("mjpg_streamer"); //判斷mjpg_streamer是否已經在運行if (-1 == ret){goto END;}else{printf("已運行mjpg_streamer,可以開始垃圾分類識別\n");}serial_fd = myserialOpen(SERIAL_DEV, BAUD);if (-1 == serial_fd) {goto END;}//開語音線程printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);pthread_create(&get_voice_tid, NULL, pget_voice, NULL);//開網絡線程pthread_create(&get_socket_tid, NULL, pget_socket, NULL);//開阿里云交互線程printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);pthread_create(&category_tid, NULL, pcategory, NULL);pthread_join(get_voice_tid, NULL);pthread_join(category_tid, NULL);pthread_join(get_socket_tid, NULL);pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);close(serial_fd);
END:garbage_final;return 0; 
}

關于TCP KeepAlive

通過設置 TCP KeepAlive 選項,可以在客戶端異常斷開連接時檢測到失效連接,并在必要時關閉它。它會自動發生在操作系統內核層面。

  1. KeepAlive 探測: 當啟用了 TCP KeepAlive 并設置了相關參數后,操作系統內核會在連接空閑指定時間(TCP_KEEPIDLE)后開始發送 KeepAlive 探測包。
  2. 檢測響應: 內核會等待客戶端對探測包的響應。如果在指定的次數(TCP_KEEPCNT)內沒有收到客戶端的響應,內核會認為該連接已經失效。
  3. 關閉連接: 當探測包沒有得到響應時,內核會自動關閉該連接,并通知應用程序。此時,你在應用程序中的 recv 調用會返回 -1,表示連接已經斷開。

oled.c

這段代碼實現了一個 OLED 顯示功能,用于在一個指定位置上顯示垃圾分類的結果。具體來說,代碼分為兩個主要部分:oled_show 函數和 myoled_init 函數。

#include <error.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>#include "oled.h"
#include "font.h"
#include "myoled.h"#define FILENAME "/dev/i2c-3"static struct display_info disp;int oled_show(void *arg)
{unsigned char *buffer = (unsigned char *)arg;//在屏幕上的指定位置顯示指定內容oled_putstrto(&disp, 0, 9+1, "This garbage is:");// 設置字體disp.font = font2;//根據 buffer[2] 的值顯示相應的垃圾分類結果switch(buffer[2]){case 0x41:oled_putstrto(&disp, 0, 20, "dry waste");break;case 0x42:oled_putstrto(&disp, 0, 20, "wet waste");break;case 0x43:oled_putstrto(&disp, 0, 20, "recyclable waste");break;case 0x44:oled_putstrto(&disp, 0, 20, "hazardous waste");break;case 0x45:oled_putstrto(&disp, 0, 20, "recognition failed");break;}// 再次設置字體disp.font = font2;//把需要顯示的內容刷新到屏幕上oled_send_buffer(&disp); return 0;
}int myoled_init(void)
{int e;// 設置顯示屏地址和字體disp.address = OLED_I2C_ADDR;disp.font = font2;// 打開和初始化 OLED 顯示屏e = oled_open(&disp, FILENAME);e = oled_init(&disp);return e;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/38901.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/38901.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/38901.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

解密tar文件解壓的Java實現技術

解密tar文件解壓的Java實現技術 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 引言 在日常的軟件開發和系統管理中&#xff0c;經常會遇到需要解壓縮文件的…

代碼隨想三刷動態規劃篇5

代碼隨想三刷動態規劃篇5 377. 組合總和 Ⅳ題目代碼 57. 爬樓梯&#xff08;第八期模擬筆試&#xff09;題目代碼 322. 零錢兌換題目代碼 279. 完全平方數題目代碼 377. 組合總和 Ⅳ 題目 鏈接 代碼 class Solution {public int combinationSum4(int[] nums, int target) {…

SM2的簽名值byte數組與ASN.1互轉

ASN.1抽象語言標記(Abstract Syntax Notation One) ASN.1是一種 ISO/ITU-T 標準,描述了一種對數據進行表示、編碼、傳輸和解碼的數據格式,它提供了一整套正規的格式用于描述對象的結構。 一、該結構的應用場景 例如在做待簽名的數字信封時,數字信封使用ASN.1封裝,這個時…

MySQL-行級鎖(行鎖、間隙鎖、臨鍵鎖)

文章目錄 1、介紹2、查看意向鎖及行鎖的加鎖情況3、行鎖的演示3.1、普通的select語句&#xff0c;執行時&#xff0c;不會加鎖3.2、select * from stu where id 1 lock in share mode;3.3、共享鎖與共享鎖之間兼容。3.4、共享鎖與排他鎖之間互斥。3.5、排它鎖與排他鎖之間互斥3…

論文調研_Awesome-Binary-Similarity

0. 概述 對 Awesome-Binary-Similarity 中列出的論文進行調研,重點總結這些論文的研究動機與未來研究方向。 1. 調研內容 論文名稱發表時間發表期刊期刊等級研究單位BinaryAI: Binary Software Composition Analysis via Intelligent Binary Source Code Matching2024年ICSE…

每日一題---OJ題:分隔鏈表

片頭 嗨&#xff01;小伙伴們&#xff0c;大家好&#xff01;今天我們一起來看看這道題----分隔鏈表 emmmm&#xff0c;這道題&#xff0c;看描述應該不算太難&#xff0c;我們一起來畫一畫圖唄&#xff01; 題目讀懂了&#xff0c;那么如何破解這道題呢&#xff1f; 思路&…

microApp vue3+vite+ts 子應用接入改造

公司做了一個平臺,使用的是microApp,需要把現有的一些系統作為子系統改造一下接入這個平臺,所以下面我說的都是子應用的改造,vue2的改造比較簡單,主要的vue3+vite+ts的改造。 參考官網 1、設置跨應用支持 vite默認開啟跨域支持,不需要額外配置。 2、注冊卸載函數 // …

nand flash spec

nand flash簡介 nand flash是一種非易失性存儲器。它具有高存儲密度、低成本和高耐用性的特點。 nand flash的特性是非易失性&#xff0c;即在電源關閉的情況下&#xff0c;數據仍然保留。 nand flash的存儲單元由浮動柵極晶體管組成&#xff0c;每個存儲單元可以存儲一位或多…

短視頻世界對我溫柔以待:成都柏煜文化傳媒有限公司

短視頻世界對我溫柔以待 在繁忙的都市生活中&#xff0c;每個人都在為生活奔波&#xff0c;為夢想努力。而在這個快節奏的時代里&#xff0c;短視頻如同一股清流&#xff0c;以其獨特的魅力&#xff0c;為我帶來了片刻的寧靜與溫柔。它像是一個無聲的朋友&#xff0c;在我疲憊…

(必看圖文)Hadoop集群安裝及MapReduce應用(手把手詳解版)

前言 隨著大數據時代的到來&#xff0c;處理和分析海量數據已成為企業和科研機構不可或缺的能力。Hadoop&#xff0c;作為開源的分布式計算平臺&#xff0c;因其強大的數據處理能力和良好的可擴展性&#xff0c;成為大數據處理領域的佼佼者。本圖文教程旨在幫助讀者理解Hadoop集…

Mysql面試合集

概念 是一個開源的關系型數據庫。 數據庫事務及其特性 事務&#xff1a;是一系列的數據庫操作&#xff0c;是數據庫應用的基本邏輯單位。 事務特性&#xff1a; &#xff08;1&#xff09;原子性&#xff1a;即不可分割性&#xff0c;事務要么全部被執行&#xff0c;要么就…

代碼隨想錄1數組

1 二分查找 Leetcode704 1 [l,r]區間 l 0, r nums.length-1; while(l<r) 因為lr有意義 2 [l,r)區間 l 0, r nums.length; while(l<r) Leetcode35 class Solution {public int searchInsert(int[] nums, int target) {int l0,rnums.length;while(l<r){int m l(…

使用設計模式來增強你的 SpringBoot 開發

SpringBoot 是一個出色的框架&#xff0c;可以快速構建強大而高效的應用程序。但你是否知道設計模式可以將 SpringBoot 開發提升到一個新的水平&#xff1f; ? 設計模式的重要性&#xff1a;了解設計模式如何促進代碼的可重用性、可維護性和整體應用程序健康。 ? SpringBoot…

在Spring Data JPA中使用@Query注解

目錄 前言示例簡單示例只查詢部分字段&#xff0c;映射到一個實體類中只查詢部分字段時&#xff0c;也可以使用List<Object[]>接收返回值再復雜一些 前言 在以往寫過幾篇spring data jpa相關的文章&#xff0c;分別是 Spring Data JPA 使用JpaSpecificationExecutor實現…

python 筆試面試八股(自用版~)

1 解釋型和編譯型語言的區別 解釋是翻譯一句執行一句&#xff0c;更靈活&#xff0c;eg&#xff1a;python; 解釋成機器能理解的指令&#xff0c;而不是二進制碼 編譯是整個源程序編譯成機器可以直接執行的二進制可運行的程序&#xff0c;再運行這個程序 比如c 2 簡述下 Pyth…

運維鍋總詳解RocketMQ

本文嘗試從Apache RocketMQ的簡介、主要組件及其作用、3種部署模式、Controller集群模式工作流程、最佳實踐等方面對其進行詳細分析。希望對您有所幫助&#xff01; 一、Apache RocketMQ 簡介 Apache RocketMQ 是一個開源的分布式消息中間件&#xff0c;由阿里巴巴集團開發并…

祝賀《華為戰略管理法:DSTE實戰體系》被《中國企業家》雜志評為企業家枕邊書50本之一(宏觀戰略類書籍)

祝賀《華為戰略管理法&#xff1a;DSTE實戰體系》被《中國企業家》雜志評為企業家枕邊書50本之一 2024年4月23日&#xff08;周二&#xff09;下午13:00&#xff0c;《中國企業家》雜志如期舉辦“每天都是讀書日”線下活動。 《中國企業家》雜志攜手商界大咖共同推選50本枕邊書…

Vue.js中的計算屬性

Vue.js中的計算屬性&#xff08;computed properties&#xff09;是用于聲明響應式依賴的屬性。它們會根據它們的依賴進行緩存&#xff0c;并且只有在相關依賴發生改變時才會重新求值。這使得它們非常適合用來處理復雜邏輯和數據處理。 基本用法 在Vue實例中&#xff0c;可以…

鐳速實現AD域集成助力企業文件安全傳輸管控

在當今這個信息量爆炸擴張的年代&#xff0c;企業數據宛如一座蘊藏無限價值的寶庫&#xff0c;它不僅是企業核心競爭力的載體&#xff0c;也成為了各種潛在風險的聚焦點。隨著數字化轉型步伐的加快&#xff0c;安全文件傳輸的管理控制顯得尤為重要&#xff0c;它構成了保護企業…

各類排序方法 歸并排序 擴展練習 逆序對數量

七月挑戰一個月重刷完Y總算法基礎題&#xff0c;并且每道題寫詳細題解 進度:(3/106) 歸并排序的思想也是分而治之 歸并優點&#xff1a;速度穩定,排序也穩定 排序也穩定&#xff08;數組中有兩個一樣的值&#xff0c;排序之后他們的前后順序不發生變化&#xff0c;我們就說…