主頁 >  其他 > Linux生產者消費者模型

Linux生產者消費者模型

2022-02-28 07:33:18 其他

文章目錄

  • 生產者消費者模型
    • 生產者消費者模型的概念
    • 生產者消費者模型的特點
    • 生產者消費者模型優點
  • 基于BlockingQueue的生產者消費者模型
    • 基于阻塞佇列的生產者消費者模型
    • 模擬實作基于阻塞佇列的生產消費模型

生產者消費者模型

生產者消費者模型的概念

生產者消費者模式就是通過一個容器來解決生產者和消費者的強耦合問題,

生產者和消費者彼此之間不直接通訊,而通過這個容器來通訊,所以生產者生產完資料之后不用等待消費者處理,直接將生產的資料放到這個容器當中,消費者也不用找生產者要資料,而是直接從這個容器里取資料,這個容器就相當于一個緩沖區,平衡了生產者和消費者的處理能力,這個容器實際上就是用來給生產者和消費者解耦的,
在這里插入圖片描述

生產者消費者模型的特點

生產者消費者模型是多執行緒同步與互斥的一個經典場景,其特點如下:

  • 三種關系: 生產者和生產者(互斥關系)、消費者和消費者(互斥關系)、生產者和消費者(互斥關系、同步關系),
  • 兩種角色: 生產者和消費者,(通常由行程或執行緒承擔)
  • 一個交易場所: 通常指的是記憶體中的一段緩沖區,(可以自己通過某種方式組織起來)

我們用代碼撰寫生產者消費者模型的時候,本質就是對這三個特點進行維護,

生產者和生產者、消費者和消費者、生產者和消費者,它們之間為什么會存在互斥關系?

介于生產者和消費者之間的容器可能會被多個執行流同時訪問,因此我們需要將該臨界資源用互斥鎖保護起來,

其中,所有的生產者和消費者都會競爭式的申請鎖,因此生產者和生產者、消費者和消費者、生產者和消費者之間都存在互斥關系,

生產者和消費者之間為什么會存在同步關系?

  • 如果讓生產者一直生產,那么當生產者生產的資料將容器塞滿后,生產者再生產資料就會生產失敗,
  • 反之,讓消費者一直消費,那么當容器當中的資料被消費完后,消費者再進行消費就會消費失敗,

雖然這樣不會造成任何資料不一致的問題,但是這樣會引起另一方的饑餓問題,是非常低效的,我們應該讓生產者和消費者訪問該容器時具有一定的順序性,比如讓生產者先生產,然后再讓消費者進行消費,

注意: 互斥關系保證的是資料的正確性,而同步關系是為了讓多執行緒之間協同起來,

生產者消費者模型優點

  • 解耦,
  • 支持并發,
  • 支持忙閑不均,

如果我們在主函式中呼叫某一函式,那么我們必須等該函式體執行完后才繼續執行主函式的后續代碼,因此函式呼叫本質上是一種緊耦合,

對應到生產者消費者模型中,函式傳參實際上就是生產者生產的程序,而執行函式體實際上就是消費者消費的程序,但生產者只負責生產資料,消費者只負責消費資料,在消費者消費期間生產者可以同時進行生產,因此生產者消費者模型本質是一種松耦合,

基于BlockingQueue的生產者消費者模型

基于阻塞佇列的生產者消費者模型

在多執行緒編程中,阻塞佇列(Blocking Queue)是一種常用于實作生產者和消費者模型的資料結構,

在這里插入圖片描述
其與普通的佇列的區別在于:

  • 當佇列為空時,從佇列獲取元素的操作將會被阻塞,直到佇列中放入了元素,
  • 當佇列滿時,往佇列里存放元素的操作會被阻塞,直到有元素從佇列中取出,

知識聯系: 看到以上阻塞佇列的描述,我們很容易想到的就是管道,而阻塞佇列最典型的應用場景實際上就是管道的實作,

模擬實作基于阻塞佇列的生產消費模型

為了方便理解,下面我們以單生產者、單消費者為例進行實作,
在這里插入圖片描述
其中的BlockQueue就是生產者消費者模型當中的交易場所,我們可以用C++STL庫當中的queue進行實作,

#include <iostream>
#include <pthread.h>
#include <queue>
#include <unistd.h>

#define NUM 5

template<class T>
class BlockQueue
{
private:
	bool IsFull()
	{
		return _q.size() == _cap;
	}
	bool IsEmpty()
	{
		return _q.empty();
	}
public:
	BlockQueue(int cap = NUM)
		: _cap(cap)
	{
		pthread_mutex_init(&_mutex, nullptr);
		pthread_cond_init(&_full, nullptr);
		pthread_cond_init(&_empty, nullptr);
	}
	~BlockQueue()
	{
		pthread_mutex_destroy(&_mutex);
		pthread_cond_destroy(&_full);
		pthread_cond_destroy(&_empty);
	}
	//向阻塞佇列插入資料(生產者呼叫)
	void Push(const T& data)
	{
		pthread_mutex_lock(&_mutex);
		while (IsFull()){
			//不能進行生產,直到阻塞佇列可以容納新的資料
			pthread_cond_wait(&_full, &_mutex);
		}
		_q.push(data);
		pthread_mutex_unlock(&_mutex);
		pthread_cond_signal(&_empty); //喚醒在empty條件變數下等待的消費者執行緒
	}
	//從阻塞佇列獲取資料(消費者呼叫)
	void Pop(T& data)
	{
		pthread_mutex_lock(&_mutex);
		while (IsEmpty()){
			//不能進行消費,直到阻塞佇列有新的資料
			pthread_cond_wait(&_empty, &_mutex);
		}
		data = _q.front();
		_q.pop();
		pthread_mutex_unlock(&_mutex);
		pthread_cond_signal(&_full); //喚醒在full條件變數下等待的生產者執行緒
	}
private:
	std::queue<T> _q; //阻塞佇列
	int _cap; //阻塞佇列最大容器資料個數
	pthread_mutex_t _mutex;
	pthread_cond_t _full;
	pthread_cond_t _empty;
};

相關說明:

  • 由于我們實作的是單生產者、單消費者的生產者消費者模型,因此我們不需要維護生產者和生產者之間的關系,也不需要維護消費者和消費者之間的關系,我們只需要維護生產者和消費者之間的同步與互斥關系即可,
  • 將BlockingQueue當中存盤的資料模板化,方便以后需要時進行復用,
  • 這里設定BlockingQueue存盤資料的上限為5,當阻塞佇列中存盤了五組資料時生產者就不能進行生產了,此時生產者就應該被阻塞,
  • 阻塞佇列是會被生產者和消費者同時訪問的臨界資源,因此我們需要用一把互斥鎖將其保護起來,
  • 生產者執行緒要向阻塞佇列當中Push資料,前提是阻塞佇列里面有空間,若阻塞佇列已經滿了,那么此時該生產者執行緒就需要進行等待,直到阻塞佇列中有空間時再將其喚醒,
  • 消費者執行緒要從阻塞佇列當中Pop資料,前提是阻塞佇列里面有資料,若阻塞佇列為空,那么此時該消費者執行緒就需要進行等待,直到阻塞佇列中有新的資料時再將其喚醒,
  • 因此在這里我們需要用到兩個條件變數,一個條件變數用來描述佇列為空,另一個條件變數用來描述佇列已滿,當阻塞佇列滿了的時候,要進行生產的生產者執行緒就應該在full條件變數下進行等待;當阻塞佇列為空的時候,要進行消費的消費者執行緒就應該在empty條件變數下進行等待,
  • 不論是生產者執行緒還是消費者執行緒,它們都是先申請到鎖進入臨界區后再判斷是否滿足生產或消費條件的,如果對應條件不滿足,那么對應執行緒就會被掛起,但此時該執行緒是拿著鎖的,為了避免死鎖問題,在呼叫pthread_cond_wait函式時就需要傳入當前執行緒手中的互斥鎖,此時當該執行緒被掛起時就會自動釋放手中的互斥鎖,而當該執行緒被喚醒時又會自動獲取到該互斥鎖,
  • 當生產者生產完一個資料后,意味著阻塞佇列當中至少有一個資料,而此時可能有消費者執行緒正在empty條件變數下進行等待,因此當生產者生產完資料后需要喚醒在empty條件變數下等待的消費者執行緒,
  • 同樣的,當消費者消費完一個資料后,意味著阻塞佇列當中至少有一個空間,而此時可能有生產者執行緒正在full條件變數下進行等待,因此當消費者消費完資料后需要喚醒在full條件變數下等待的生產者執行緒,

判斷是否滿足生產消費條件時不能用if,而應該用while:

  • pthread_cond_wait函式是讓當前執行流進行等待的函式,是函式就意味著有可能呼叫失敗,呼叫失敗后該執行流就會繼續往后執行,
  • 其次,在多消費者的情況下,當生產者生產了一個資料后如果使用pthread_cond_broadcast函式喚醒消費者,就會一次性喚醒多個消費者,但待消費的資料只有一個,此時其他消費者就被偽喚醒了,
  • 為了避免出現上述情況,我們就要讓執行緒被喚醒后再次進行判斷,確認是否真的滿足生產消費條件,因此這里必須要用while進行判斷,

在主函式中我們就只需要創建一個生產者執行緒和一個消費者執行緒,讓生產者執行緒不斷生產資料,讓消費者執行緒不斷消費資料,

#include "BlockQueue.hpp"

void* Producer(void* arg)
{
	BlockQueue<int>* bq = (BlockQueue<int>*)arg;
	//生產者不斷進行生產
	while (true){
		sleep(1);
		int data = rand() % 100 + 1;
		bq->Push(data); //生產資料
		std::cout << "Producer: " << data << std::endl;
	}
}
void* Consumer(void* arg)
{
	BlockQueue<int>* bq = (BlockQueue<int>*)arg;
	//消費者不斷進行消費
	while (true){
		sleep(1);
		int data = 0;
		bq->Pop(data); //消費資料
		std::cout << "Consumer: " << data << std::endl;
	}
}
int main()
{
	srand((unsigned int)time(nullptr));
	pthread_t producer, consumer;
	BlockQueue<int>* bq = new BlockQueue<int>;
	//創建生產者執行緒和消費者執行緒
	pthread_create(&producer, nullptr, Producer, bq);
	pthread_create(&consumer, nullptr, Consumer, bq);

	//join生產者執行緒和消費者執行緒
	pthread_join(producer, nullptr);
	pthread_join(consumer, nullptr);
	delete bq
	return 0;
}

相關說明:

  • 阻塞佇列要讓生產者執行緒向佇列中Push資料,讓消費者執行緒從佇列中Pop資料,因此這個阻塞佇列必須要讓這兩個執行緒同時看到,所以我們在創建生產者執行緒和消費者執行緒時,需要將該阻塞佇列作為執行緒執行例程的引數進行傳入,
  • 代碼中生產者生產資料就是將獲取到的亂數Push到阻塞佇列,而消費者消費資料就是從阻塞佇列Pop資料,為了便于觀察,我們可以將生產者生產的資料和消費者消費的資料進行列印輸出,

生產者消費者步調一致

由于代碼中生產者是每隔一秒生產一個資料,而消費者是每隔一秒消費一個資料,因此運行代碼后我們可以看到生產者和消費者的執行步調是一致的,
在這里插入圖片描述
小貼士:.hpp為后綴的檔案也是頭檔案,該頭檔案同時包含類的定義與實作,呼叫者只需include該hpp檔案即可,因為開源專案一般不需要進行保護,所以在開源專案中用的比較多,

生產者生產的快,消費者消費的慢

我們可以讓生產者不停的進行生產,而消費者每隔一秒進行消費,

void* Producer(void* arg)
{
	BlockQueue<int>* bq = (BlockQueue<int>*)arg;
	//生產者不斷進行生產
	while (true){
		int data = rand() % 100 + 1;
		bq->Push(data); //生產資料
		std::cout << "Producer: " << data << std::endl;
	}
}
void* Consumer(void* arg)
{
	BlockQueue<int>* bq = (BlockQueue<int>*)arg;
	//消費者不斷進行消費
	while (true){
		sleep(1);
		int data = 0;
		bq->Pop(data); //消費資料
		std::cout << "Consumer: " << data << std::endl;
	}
}

此時由于生產者生產的很快,運行代碼后一瞬間生產者就將阻塞佇列打滿了,此時生產者想要再進行生產就只能在full條件變數下進行等待,直到消費者消費完一個資料后,生產者才會被喚醒進而繼續進行生產,生產者生產完一個資料后又會進行等待,因此后續生產者和消費者的步調又變成一致的了,
在這里插入圖片描述

生產者生產的慢,消費者消費的快

當然,我們也可以讓生產者每隔一秒進行生產,而消費者不停的進行消費,

void* Producer(void* arg)
{
	BlockQueue<int>* bq = (BlockQueue<int>*)arg;
	//生產者不斷進行生產
	while (true){
		sleep(1);
		int data = rand() % 100 + 1;
		bq->Push(data); //生產資料
		std::cout << "Producer: " << data << std::endl;
	}
}
void* Consumer(void* arg)
{
	BlockQueue<int>* bq = (BlockQueue<int>*)arg;
	//消費者不斷進行消費
	while (true){
		int data = 0;
		bq->Pop(data); //消費資料
		std::cout << "Consumer: " << data << std::endl;
	}
}

雖然消費者消費的很快,但一開始阻塞佇列中是沒有資料的,因此消費者只能在empty條件變數下進行等待,直到生產者生產完一個資料后,消費者才會被喚醒進而進行消費,消費者消費完這一個資料后又會進行等待,因此生產者和消費者的步調就是一致的,
在這里插入圖片描述

滿足某一條件時再喚醒對應的生產者或消費者

我們也可以當阻塞佇列當中存盤的資料大于佇列容量的一半時,再喚醒消費者執行緒進行消費;當阻塞佇列當中存盤的資料小于佇列容器的一半時,再喚醒生產者執行緒進行生產,

//向阻塞佇列插入資料(生產者呼叫)
void Push(const T& data)
{
	pthread_mutex_lock(&_mutex);
	while (IsFull()){
		//不能進行生產,直到阻塞佇列可以容納新的資料
		pthread_cond_wait(&_full, &_mutex);
	}
	_q.push(data);
	if (_q.size() >= _cap / 2){
		pthread_cond_signal(&_empty); //喚醒在empty條件變數下等待的消費者執行緒
	}
	pthread_mutex_unlock(&_mutex);
}
//從阻塞佇列獲取資料(消費者呼叫)
void Pop(T& data)
{
	pthread_mutex_lock(&_mutex);
	while (IsEmpty()){
		//不能進行消費,直到阻塞佇列有新的資料
		pthread_cond_wait(&_empty, &_mutex);
	}
	data = _q.front();
	_q.pop();
	if (_q.size() <= _cap / 2){
		pthread_cond_signal(&_full); //喚醒在full條件變數下等待的生產者執行緒
	}
	pthread_mutex_unlock(&_mutex);
}

我們仍然讓生產者生產的快,消費者消費的慢,運行代碼后生產者還是一瞬間將阻塞佇列打滿后進行等待,但此時不是消費者消費一個資料就喚醒生產者執行緒,而是當阻塞佇列當中的資料小于佇列容器的一半時,才會喚醒生產者執行緒進行生產,
在這里插入圖片描述

基于計算任務的生產者消費者模型

當然,實際使用生產者消費者模型時可不是簡單的讓生產者生產一個數字讓消費者進行列印而已,我們這樣做只是為了測驗代碼的正確性,
由于我們將BlockingQueue當中存盤的資料進行了模板化,此時就可以讓BlockingQueue當中存盤其他型別的資料,

例如,我們想要實作一個基于計算任務的生產者消費者模型,此時我們只需要定義一個Task類,這個類當中需要包含一個Run成員函式,該函式代表著我們想讓消費者如何處理拿到的資料,

#pragma once
#include <iostream>

class Task
{
public:
	Task(int x = 0, int y = 0, int op = 0)
		: _x(x), _y(y), _op(op)
	{}
	~Task()
	{}
	void Run()
	{
		int result = 0;
		switch (_op)
		{
		case '+':
			result = _x + _y;
			break;
		case '-':
			result = _x - _y;
			break;
		case '*':
			result = _x * _y;
			break;
		case '/':
			if (_y == 0){
				std::cout << "Warning: div zero!" << std::endl;
				result = -1;
			}
			else{
				result = _x / _y;
			}
			break;
		case '%':
			if (_y == 0){
				std::cout << "Warning: mod zero!" << std::endl;
				result = -1;
			}
			else{
				result = _x % _y;
			}
			break;
		default:
			std::cout << "error operation!" << std::endl;
			break;
		}
		std::cout << _x << _op << _y << "=" << result << std::endl;
	}
private:
	int _x;
	int _y;
	char _op;
};

此時生產者放入阻塞佇列的資料就是一個Task物件,而消費者從阻塞佇列拿到Task物件后,就可以用該物件呼叫Run成員函式進行資料處理,

void* Producer(void* arg)
{
	BlockQueue<Task>* bq = (BlockQueue<Task>*)arg;
	const char* arr = "+-*/%";
	//生產者不斷進行生產
	while (true){
		int x = rand() % 100;
		int y = rand() % 100;
		char op = arr[rand() % 5];
		Task t(x, y, op);
		bq->Push(t); //生產資料
		std::cout << "producer task done" << std::endl;
	}
}
void* Consumer(void* arg)
{
	BlockQueue<Task>* bq = (BlockQueue<Task>*)arg;
	//消費者不斷進行消費
	while (true){
		sleep(1);
		Task t;
		bq->Pop(t); //消費資料
		t.Run(); //處理資料
	}
}

運行代碼,當阻塞佇列被生產者打滿后消費者被喚醒,此時消費者在消費資料時執行的就是計算任務,當阻塞佇列當中的資料被消費到低于一定閾值后又會喚醒生產者進行生產,
在這里插入圖片描述
也就是說,此后我們想讓生產者消費者模型處理某一種任務時,就只需要提供對應的Task類,然后讓該Task類提供一個對應的Run成員函式告訴我們應該如何處理這個任務即可,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/433399.html

標籤:其他

上一篇:R語言為dataframe添加新的資料列(橫向拼接、Appending columns,Unioning columns):使用R原生方法、data.table、dplyr等方案

下一篇:淺談BiFPN結構并在mmdetection中從Registry開始逐步實作

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more