第19ç« å¹¶å
# 第19ç« å¹¶å
ä»é¿è¿æ¥çï¼ç¨å 许ä¸åéå¶å°ä½¿ç¨åå¨ä½ç½®åå ¶å°åçé¢åæºå¨çè¯è¨ç¼å大åå¹¶åç¨åºå¹¶ä¸å¯åãå³ä¾¿åå©å¤æç硬件æºå¶ï¼æä»¬ä¹æ ¹æ¬æ æ³è®©è¿ç±»ç¨åºåå¾å¯é ã ââ佩å°Â·å¸æå¥Â·æ±æ£®ï¼1977å¹´ï¼
é信模å¼å³å¹¶è¡æ¨¡å¼ã ââæ ç¹Â·è«éæ¯
妿å¨ä½ çèä¸ç涯ä¸ï¼å¯¹å¹¶åç¼ç¨çæåº¦ææè½¬åï¼é£ä½ å¹¶ä¸å¤åï¼è¿æ¯å¾å¸¸è§çæ åµã
èµ·åï¼ç¼åå¹¶å代ç è½»æ¾åæè¶£ã线ç¨ãéãéåçå·¥å ·å¾å®¹æä¸æä½¿ç¨ãç¡®å®ï¼å ¶ä¸åå¨è¯¸å¤é·é±ï¼ä½å¥½å¨ä½ æ¸ æ¥å®ä»¬æ¯ä»ä¹ï¼å¹¶ä¸ä¼å°å¿é¿å ç¯éã
å¨æä¸ªé¶æ®µï¼ä½ å¾è°è¯å«äººåçå¤çº¿ç¨ä»£ç ï¼ç¶åä¸å¾ä¸æ¿è®¤ï¼æäºäººççä¸éåç¨è¿äºå·¥å ·ã
æ¥çï¼åå°äºè°è¯èªå·±å¤çº¿ç¨ä»£ç çæ¶åã
ç»éªä¼è®©ä½ 对ææå¤çº¿ç¨ä»£ç 产çä¸ç§åççæçï¼çè³æ¯å½»åºçæç主ä¹ãæ¶ä¸æ¶å°±ä¼ææç« ç¨ä»¤äººå¤´ç¼çç»èè§£éï¼ä¸ºä»ä¹æäºçä¼¼æ£ç¡®çå¤çº¿ç¨ç¼ç¨ä¹ æ¯ç¨æ³æ ¹æ¬è¡ä¸éï¼è¿ä¸ âå 忍¡åâ æå ³ï¼ï¼è¿è¿ä¸æ¥å æ·±äºä½ çè¿ç§æçã使ç»ï¼ä½ 伿¾å°ä¸ç§èªè®¤ä¸ºå¨å®é 使ç¨ä¸ä¸ä¼é¢ç¹åºéçå¹¶åç¼ç¨æ¹æ³ãä½ å ä¹å¯ä»¥ææææ åµé½å¥ç¨å°è¿ç§æ¹æ³ä¸ï¼èä¸ï¼è¦æ¯ä½ ççå¾å害ï¼è¿è½å¦ä¼å¯¹å¢å ç夿æ§è¯´ âä¸âã
å½ç¶ï¼å¹¶åç¼ç¨çæ¹æ³æå¾å¤ãç³»ç»ç¨åºå常ç¨çæ¹æ³å æ¬ä»¥ä¸å ç§ï¼
- ä¸ä¸ªåå°çº¿ç¨æ§è¡åä¸ä»»å¡ï¼å¹¶å®æå¤éæ§è¡è¯¥ä»»å¡ã
- éç¨çå·¥ä½çº¿ç¨æ± ï¼éè¿ä»»å¡éåä¸å®¢æ·ç«¯è¿è¡éä¿¡ã
- æµæ°´çº¿å¼å¤çï¼æ°æ®ä»ä¸ä¸ªçº¿ç¨æµåå¦ä¸ä¸ªçº¿ç¨ï¼æ¯ä¸ªçº¿ç¨å®æä¸é¨åå·¥ä½ã
- æ°æ®å¹¶è¡å¤çï¼å³åå®ï¼æ 论æ£ç¡®ä¸å¦ï¼æ´ä¸ªè®¡ç®æºä¸»è¦æ§è¡ä¸ä¸ªå¤§å计ç®ä»»å¡ï¼å æ¤å°å
¶æåæ
n个é¨åï¼å¨n个线ç¨ä¸è¿è¡ï¼ææè½è®©æºå¨çæænä¸ªæ ¸å¿åæ¶æå ¥å·¥ä½ã - 大éåæ¥å¯¹è±¡ï¼å¤ä¸ªçº¿ç¨å¯ä»¥è®¿é®ç¸åçæ°æ®ï¼éè¿åºäºäºæ¥éçåºå±åè¯ç临æ¶é宿¹æ¡æ¥é¿å ç«ææ¡ä»¶ãï¼Javaå ç½®äºå¯¹è¿ç§æ¨¡åçæ¯æï¼å¨20ä¸çºª90年代å21ä¸çºªåï¼è¿ç§æ¨¡åé常æµè¡ãï¼
- ååæ´æ°æä½ï¼å 许å¤ä¸ªæ ¸å¿éè¿ä¸ä¸ªæºå¨å大å°çåæ®µä¼ éä¿¡æ¯è¿è¡éä¿¡ãï¼è¿ç§æ¹å¼æ¯å ¶ä»æææ¹å¼é½æ´é¾æ£ç¡®å®ç°ï¼é¤éæ£å¨äº¤æ¢çæ°æ®ç¡®å®åªæ¯æ´æ°å¼ãå¨å®é åºç¨ä¸ï¼éå¸¸æ¯æéãï¼
éçæ¶é´çæ¨ç§»ï¼ä½ å¯è½ä¼ææ¡å ¶ä¸å ç§æ¹æ³ï¼å¹¶è½å®å ¨å°å°å®ä»¬ç»åèµ·æ¥ãä½ æäºè¿é¨èºæ¯ç大å¸ãè¦æ¯å ¶ä»äººæ°¸è¿é½ä¸è¢«å è®¸ä»¥ä»»ä½æ¹å¼ä¿®æ¹ç³»ç»ï¼ä¸åå°±é½å®ç¾äºãé£äºçº¿ç¨è¿ç¨å¾å½çç¨åºéå æ»¡äºä¸ææçè§åã
Rustæä¾äºä¸ç§æ´å¥½çå¹¶åç¼ç¨æ¹å¼ï¼å®ä¸æ¯å¼ºè¿«ææç¨åºéç¨åä¸é£æ ¼ï¼è¿å¯¹ç³»ç»ç¨åºåæ¥è¯´æ ¹æ¬ä¸æ¯è§£å³æ¹æ¡ï¼ï¼èæ¯å®å ¨å°æ¯æå¤ç§é£æ ¼ãé£äºä¸ææçè§å被åè¿äºä»£ç éï¼å¹¶ç±ç¼è¯å¨å¼ºå¶æ§è¡ã
ä½ å¯è½å¬è¯´è¿ï¼Rustè½è®©ä½ ç¼åå®å ¨ãå¿«éçå¹¶åç¨åºãæ¬ç« å°±æ¥åè¯ä½ å¦ä½å®ç°ãæä»¬å°ä»ç»ä½¿ç¨Rust线ç¨çä¸ç§æ¹å¼ï¼
- åæ²»å¹¶è¡ï¼Fork - join parallelismï¼
- ééï¼Channelsï¼
- å ±äº«å¯åç¶æï¼Shared mutable stateï¼
å¨è¿ä¸ªè¿ç¨ä¸ï¼ä½ ä¼ç¨å°ç®åæå¦çå ³äºRustè¯è¨çææç¥è¯ãRustå¨å¼ç¨ãå¯åæ§åçå½å¨ææ¹é¢çä¸¥æ ¼å¤çï¼å¨å线ç¨ç¨åºä¸å°±å¾æä»·å¼ï¼èå¨å¹¶åç¼ç¨ä¸ï¼è¿äºè§åççæ£æä¹æå¾ä»¥å¸æ¾ãå®ä»¬è®©ä½ è½å¤æ©å èªå·±çç¼ç¨å·¥å ·åºï¼å¿«é䏿£ç¡®å°ç¼åå¤ç§é£æ ¼çå¤çº¿ç¨ä»£ç ï¼æ éæçï¼æ éæ å¿§ã
# åæ²»å¹¶è¡
彿å 个å®å ¨ç¬ç«ç任塿³è¦åæ¶æ§è¡æ¶ï¼å°±ä¼åºç°çº¿ç¨æç®åçç¨ä¾ã
ä¾å¦ï¼å设æä»¬è¦å¯¹ä¸ä¸ªå¤§åææ¡£è¯æåºè¿è¡èªç¶è¯è¨å¤çãæä»¬å¯ä»¥ç¼åä¸ä¸ªå¾ªç¯ï¼
fn process_files(filenames: Vec<String>) -> io::Result<()> {
for document in filenames {
let text = load(&document)?; // è¯»åæºæä»¶
let results = process(text); // 计ç®ç»è®¡ä¿¡æ¯
save(&document, results)?; // åå
¥è¾åºæä»¶
}
Ok(())
}
2
3
4
5
6
7
8
该ç¨åºçè¿è¡è¿ç¨å¦å¾19 - 1æç¤ºã
å¾19 - 1. process_files()çåçº¿ç¨æ§è¡
ç±äºæ¯ä¸ªææ¡£é½æ¯åç¬å¤ççï¼æä»¥éè¿å°è¯æåºåæå¤ä¸ªåï¼å¹¶å¨ä¸å线ç¨ä¸å¤çæ¯ä¸ªåï¼ç¸å¯¹å®¹æå å¿«è¿ä¸ªä»»å¡çé度ï¼å¦å¾19 - 2æç¤ºã
è¿ç§æ¨¡å¼ç§°ä¸ºå治并è¡ï¼Fork - join parallelismï¼ãâåæ²»ï¼forkï¼â æå¯å¨ä¸ä¸ªæ°çº¿ç¨ï¼âåå¹¶ï¼joinï¼â æçå¾ çº¿ç¨å®æãæä»¬ä¹åè§è¿è¿ç§ææ¯ï¼å¨ç¬¬2ç« ä¸ï¼æä»¬ç¨å®æ¥å 鿼德叿´ç¹éåç»å¶ç¨åºã
åæ²»å¹¶è¡æå 个å¸å¼äººçå°æ¹ï¼
æå ¶ç®åï¼å治并è¡å¾å®¹æå®ç°ï¼èä¸Rustè®©å ¶æ£ç¡®å®ç°ä¹åå¾è½»æ¾ã
é¿å ç¶é¢ï¼å治并è¡ä¸ä¸åå¨å¯¹å ±äº«èµæºçéå®ãä»»ä½çº¿ç¨å¯ä¸éè¦çå¾ å ¶ä»çº¿ç¨çæ¶åæ¯å¨æåã卿¤æé´ï¼æ¯ä¸ªçº¿ç¨é½è½èªç±è¿è¡ï¼è¿æå©äºéä½ä»»å¡åæ¢çå¼éã
æ§è½è®¡ç®ç´è§ï¼å¨çæ³æ åµä¸ï¼å¯å¨å个线ç¨ï¼æä»¬å°±è½å¨ååä¹ä¸çæ¶é´å 宿工ä½ãå¾19 - 2å±ç¤ºäºæä»¬ä¸è½ææè¾¾å°è¿ç§çæ³å 鿝çä¸ä¸ªåå ï¼æä»¬å¯è½æ æ³å°å·¥ä½å¹³ååé å°ææçº¿ç¨ä¸ãå¦ä¸ä¸ªéè¦è°¨æ å¯¹å¾ çåå æ¯ï¼ææ¶å治并è¡ç¨åºå¨çº¿ç¨åå¹¶åï¼å¿ é¡»è±è´¹ä¸äºæ¶é´æ¥å并线ç¨è®¡ç®åºçç»æãä¹å°±æ¯è¯´ï¼å®å ¨é离任å¡å¯è½ä¼äº§çä¸äºé¢å¤å·¥ä½ãå³ä¾¿å¦æ¤ï¼é¤äºè¿ä¸¤ç¹ä¹å¤ï¼ä»»ä½å ·æç¬ç«å·¥ä½åå ä¸åCPUéå¶çç¨åºé½ææè·å¾æ¾èçæ§è½æåã
æäºæ¨æç¨åºæ£ç¡®æ§ï¼åªè¦çº¿ç¨çæ£ç¸äºéç¦»ï¼æ¯å¦æ¼å¾·å¸æ´ç¹ç¨åºä¸ç计ç®çº¿ç¨ï¼å治并è¡ç¨åºå°±æ¯ç¡®å®æ§çãæ è®ºçº¿ç¨é度å¦ä½ååï¼ç¨åºæ»æ¯äº§çç¸åçç»æãè¿æ¯ä¸ç§æ²¡æç«ææ¡ä»¶ç并忍¡åã
å¾19 - 2. 使ç¨åæ²»å¹¶è¡æ¹æ³çå¤çº¿ç¨æä»¶å¤ç
åæ²»å¹¶è¡ç主è¦ç¼ºç¹æ¯å®è¦æ±å·¥ä½åå æ¯ç¬ç«çã卿¬ç« åé¢ï¼æä»¬ä¼æ¢è®¨ä¸äºä¸å¤ªå®¹æåå²çé®é¢ã
ç®åï¼è®©æä»¬ç»§ç»ä»¥èªç¶è¯è¨å¤ç为ä¾ãæä»¬å°å±ç¤ºå ç§æåæ²»å¹¶è¡æ¨¡å¼åºç¨å°process_files彿°çæ¹æ³ã
# spawnåjoin
std::thread::spawn彿°ç¨äºå¯å¨ä¸ä¸ªæ°çº¿ç¨ï¼
use std::thread;
thread::spawn(|| {
println!("hello from a child thread");
});
2
3
4
5
宿¥åä¸ä¸ªåæ°ï¼å³ä¸ä¸ªå®ç°äºFnOnceçéå
æå½æ°ãRustä¼å¯å¨ä¸ä¸ªæ°çº¿ç¨æ¥è¿è¡è¯¥éå
æå½æ°ä¸ç代ç ãæ°çº¿ç¨æ¯ä¸ä¸ªçæ£çæä½ç³»ç»çº¿ç¨ï¼æ¥æèªå·±çæ ï¼è¿åC++ãC#以åJavaä¸ç线ç¨ä¸æ ·ã
ä¸é¢æ¯ä¸ä¸ªæ´å
·ä½ç示ä¾ï¼ä½¿ç¨spawnå®ç°ä¹åprocess_files彿°çå¹¶è¡çæ¬ï¼
use std::{thread, io};
fn process_files_in_parallel(filenames: Vec<String>) -> io::Result<()> {
// å°å·¥ä½åå为å¤ä¸ªåã
const NTHREADS: usize = 8;
let worklists = split_vec_into_chunks(filenames, NTHREADS);
// åæ²»ï¼Forkï¼ï¼å¯å¨ä¸ä¸ªçº¿ç¨æ¥å¤çæ¯ä¸ªåã
let mut thread_handles = vec![];
for worklist in worklists {
thread_handles.push(
thread::spawn(move || process_files(worklist))
);
}
// åå¹¶ï¼Joinï¼ï¼çå¾
ææçº¿ç¨å®æã
for handle in thread_handles {
handle.join().unwrap()?;
}
Ok(())
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
æä»¬éè¡åæè¿ä¸ªå½æ°ã
fn process_files_in_parallel(filenames: Vec<String>) -> io::Result<()> {
æä»¬çæ°å½æ°ä¸åå§çprocess_files彿°å
·æç¸åçç±»åç¾åï¼è¿ä½¿å¾å®å¯ä»¥å¾æ¹ä¾¿å°ç´æ¥æ¿æ¢å彿°ã
// Divide the work into several chunks.
const NTHREADS: usize = 8;
let worklists = split_vec_into_chunks(filenames, NTHREADS);
2
3
æä»¬ä½¿ç¨äºä¸ä¸ªæªå¨æ¤å¤å±ç¤ºçå·¥å
·å½æ°split_vec_into_chunksæ¥ååå·¥ä½ãç»æworklistsæ¯ä¸ä¸ªåéçåéï¼å®å
å«äºåå§åéfilenamesååååçå
«ä¸ªé¨åã
// Fork: Spawn a thread to handle each chunk.
let mut thread_handles = vec![];
for worklist in worklists {
thread_handles.push(
thread::spawn(move || process_files(worklist))
);
}
2
3
4
5
6
7
æä»¬ä¸ºæ¯ä¸ªå·¥ä½å表å¯å¨ä¸ä¸ªçº¿ç¨ãspawn()彿°è¿åä¸ä¸ªå为JoinHandleçå¼ï¼æä»¬ç¨åä¼ç¨å°å®ãç®åï¼æä»¬æææçJoinHandleåå
¥ä¸ä¸ªåéä¸ã
注ææä»¬æ¯å¦ä½å°æä»¶ååè¡¨ä¼ éå°å·¥ä½çº¿ç¨ä¸çï¼
worklistç±ç¶çº¿ç¨ä¸çfor循ç¯å®ä¹å¹¶å¡«å æ°æ®ã- 䏿¦å建äº
moveéå ï¼worklistå°±ä¼è¢«ç§»å¨å°éå ä¸ã - ç¶å
spawnå°éå ï¼å æ¬workliståéï¼ç§»å¨å°æ°çå线ç¨ä¸ã
è¿äºç§»å¨æä½çå¼éå¾å°ãå°±åæä»¬å¨ç¬¬4ç« è®¨è®ºçVec<String>çç§»å¨ä¸æ ·ï¼Stringä¸ä¼è¢«å
éãå®é
ä¸ï¼æ²¡æè¿è¡ä»»ä½å
ååé
æéæ¾æä½ãå¯ä¸ç§»å¨çæ°æ®æ¯Vecæ¬èº«ï¼å ç¨ä¸ä¸ªæºå¨åã
大夿°æ åµä¸ï¼ä½ åå»ºçæ¯ä¸ªçº¿ç¨é½éè¦ä»£ç åæ°æ®æè½å¼å§è¿è¡ãRustçéå 徿¹ä¾¿ï¼å®å¯ä»¥å å«ä½ æ³è¦çä»»ä½ä»£ç åæ°æ®ã
ç»§ç»çä¸é¢ç代ç ï¼
// Join: Wait for all threads to finish.
for handle in thread_handles {
handle.join().unwrap()?;
}
2
3
4
æä»¬ä½¿ç¨ä¹åæ¶éçJoinHandleç.join()æ¹æ³ï¼çå¾
ææå
«ä¸ªçº¿ç¨å®æä»»å¡ã
çå¾
线ç¨å®æé常æ¯ç¡®ä¿ç¨åºæ£ç¡®æ§çå¿
è¦æä½ï¼å 为Rustç¨åºä¸æ¦main彿°è¿åå°±ä¼éåºï¼å³ä½¿å
¶ä»çº¿ç¨ä»å¨è¿è¡ãææå½æ°ä¸ä¼è¢«è°ç¨ï¼å¤ä½ç线ç¨ä¼ç´æ¥è¢«ç»æ¢ãå¦æä½ ä¸å¸æåºç°è¿ç§æ
åµï¼å¡å¿
å¨ä»main彿°è¿åä¹åï¼çå¾
ä½ å
³å¿çææçº¿ç¨å®æã
妿æä»¬æåæ§è¡å®è¿ä¸ªå¾ªç¯ï¼å°±æå³çææå
«ä¸ªå线ç¨é½æå宿äºä»»å¡ãå æ¤ï¼æä»¬ç彿°æåè¿åOk(())ï¼
Ok(())
}
2
# 跨线ç¨é误å¤ç
卿们ç示ä¾ä¸ï¼ç¨äºçå¾ å线ç¨å®æçä»£ç æ¯çèµ·æ¥è¦å¤æï¼è¿æ¯å 为æ¶åå°é误å¤çãæä»¬åæ¥çä¸ä¸è¿è¡ä»£ç ï¼
handle.join().unwrap()?;
.join()æ¹æ³ä¸ºæä»¬åäºä¸¤ä»¶å¾å·§å¦çäºæ
ã
第ä¸ï¼handle.join()è¿åä¸ä¸ªstd::thread::Resultï¼å¦æå线ç¨åçäºææ
ï¼panicï¼ï¼è¿ä¸ªç»æå°±ä¼æ¯ä¸ä¸ªé误ãè¿ä½¿å¾Rustä¸ççº¿ç¨æ¯C++ä¸ç线ç¨å¥å£®å¾å¤ãå¨C++ä¸ï¼æ°ç»è¶ç访é®å±äºæªå®ä¹è¡ä¸ºï¼å¹¶ä¸æ æ³ä¿æ¤ç³»ç»çå
¶ä»é¨åä¸åå
¶å½±åãå¨Rustä¸ï¼ææ
æ¯çº¿ç¨å®å
¨çï¼çº¿ç¨ä¹é´çè¾¹ç就忿
çé²ç«å¢ä¸æ ·ï¼ææ
ä¸ä¼èªå¨ä»ä¸ä¸ªçº¿ç¨ä¼ æå°ä¾èµå®çå
¶ä»çº¿ç¨ãç¸åï¼ä¸ä¸ªçº¿ç¨ä¸çææ
ä¼å¨å
¶ä»çº¿ç¨ä¸ä½ä¸ºéè¯¯ç»ææ¥åãè¿æ ·æ´ä¸ªç¨åºå¯ä»¥å¾å®¹æå°æ¢å¤ã
ä¸è¿ï¼å¨æä»¬çç¨åºä¸ï¼æä»¬å¹¶æ²¡æå°è¯è¿è¡å¤æçææ
å¤çãç¸åï¼æä»¬ç´æ¥å¯¹è¿ä¸ªResult使ç¨.unwrap()ï¼æè¨å®æ¯Okç»æè䏿¯Errç»æã妿æä¸ªå线ç¨åçäºææ
ï¼é£ä¹è¿ä¸ªæè¨å°±ä¼å¤±è´¥ï¼è¿è导è´ç¶çº¿ç¨ä¹åçææ
ãæä»¬æ¾å¼å°å°å线ç¨çææ
ä¼ éç»äºç¶çº¿ç¨ã
第äºï¼handle.join()ä¼å°å线ç¨çè¿åå¼ä¼ éåç¶çº¿ç¨ãæä»¬ä¼ éç»spawnçéå
è¿åç±»åæ¯io::Result<()>ï¼å 为process_filesçè¿åç±»åå°±æ¯è¿æ ·ãè¿ä¸ªè¿åå¼ä¸ä¼è¢«ä¸¢å¼ãå½å线ç¨å®æä»»å¡æ¶ï¼å®çè¿åå¼ä¼è¢«ä¿å䏿¥ï¼JoinHandle::join()ä¼å°è¿ä¸ªå¼ä¼ éåç¶çº¿ç¨ã
å¨è¿ä¸ªç¨åºä¸ï¼handle.join()è¿åç宿´ç±»åæ¯std::thread::Result<std::io::Result<()>>ãå
¶ä¸thread::Resultæ¯spawn/join APIçä¸é¨åï¼èio::Resultæ¯æä»¬åºç¨ç¨åºçä¸é¨åã
卿们çä¾åä¸ï¼å¨è§£å
thread::Resultä¹åï¼æä»¬å¯¹io::Result使ç¨?æä½ç¬¦ï¼æ¾å¼å°å°å线ç¨ä¸çI/Oéè¯¯ä¼ éç»ç¶çº¿ç¨ã
è¿ä¸åçèµ·æ¥å¯è½ç¸å½å¤æãä½è¦ç¥éè¿åªæ¯ä¸è¡ä»£ç ï¼ååå
¶ä»è¯è¨å¯¹æ¯ä¸ä¸ãå¨JavaåC#ä¸ï¼å线ç¨ä¸çå¼å¸¸é»è®¤ä¼è¢«è¾åºå°ç»ç«¯ç¶å被忽ç¥ãå¨C++ä¸ï¼é»è®¤åæ³æ¯ç»æ¢è¿ç¨ãå¨Rustä¸ï¼é误æ¯Resultå¼ï¼æ°æ®ï¼è䏿¯å¼å¸¸ï¼æ§å¶æµï¼ãå®ä»¬åå
¶ä»ä»»ä½å¼ä¸æ ·å¨ä¸å线ç¨ä¹é´ä¼ éã任使¶åä½ ä½¿ç¨åºå±çº¿ç¨APIï¼æç»é½å¾ç¼åä»ç»çé误å¤ç代ç ï¼ä¸è¿æ¢ç¶å¿
é¡»è¦åï¼æResultç±»åå°±æ¹ä¾¿å¤äºã
# 跨线ç¨å ±äº«ä¸å¯åæ°æ®
å设æä»¬æ£å¨è¿è¡çåæéè¦ä¸ä¸ªå å«å¤§éè±è¯åè¯åçè¯çæ°æ®åºï¼
// ä¹å
fn process_files(filenames: Vec<String>)
// ä¹å
fn process_files(filenames: Vec<String>, glossary: &GigabyteMap)
2
3
4
è¿ä¸ªæ¯è¯è¡¨ä¼éå¸¸å¤§ï¼æä»¥æä»¬éè¿å¼ç¨ä¼ éå®ãé£ä¹å¦ä½ä¿®æ¹process_files_in_parallel彿°ï¼ä»¥ä¾¿å°æ¯è¯è¡¨ä¼ éç»å·¥ä½çº¿ç¨å¢ï¼
ç´æ¥ä¿®æ¹çæ¹æ³è¡ä¸éï¼
fn process_files_in_parallel(filenames: Vec<String>,
glossary: &GigabyteMap)
-> io::Result<()>
{
...
for worklist in worklists {
thread_handles.push(
spawn(move || process_files(worklist, glossary)) // é误
);
}
...
}
2
3
4
5
6
7
8
9
10
11
12
æä»¬åªæ¯å¨å½æ°ä¸æ·»å äºä¸ä¸ªglossaryåæ°ï¼å¹¶å°å
¶ä¼ éç»process_filesãRust伿¥éï¼
error[E0621]: explicit lifetime required in the type of `glossary`
--> src/lib.rs:75:17
|
------------
61 | glossary: &GigabyteMap)
`'static` to the BTreeMap<String,
help: add explicit lifetime
type of `glossary`: `&'static String>`
...
75| glossary))
2
3
4
5
6
7
8
9
10
Rustæ±æ¨æä»¬ä¼ éç»spawnçéå
ççå½å¨ææé®é¢ï¼èç¼è¯å¨ç»åºçè¿ä¸ª â帮å©â ä¿¡æ¯å®é
䏿²¡ä»ä¹ç¨ã
spawnä¼å¯å¨ç¬ç«ç线ç¨ãRustæ æ³ç¥éå线ç¨ä¼è¿è¡å¤é¿æ¶é´ï¼æä»¥å®ä¼åæåçå设ï¼å®å设å线ç¨å¯è½å¨ç¶çº¿ç¨ç»æä¸ç¶çº¿ç¨ä¸çææå¼é½æ¶å¤±ä¹åä»ç¶ç»§ç»è¿è¡ãæ¾ç¶ï¼å¦æå线ç¨è¦è¿è¡é£ä¹ä¹
ï¼å®æè¿è¡çéå
ä¹å¾æç»é£ä¹ä¹
ã使¯è¿ä¸ªéå
ççå½å¨ææ¯æéçï¼å®ä¾èµäºglossaryè¿ä¸ªå¼ç¨ï¼èå¼ç¨ä¸ä¼ä¸ç´åå¨ã
注æï¼Rustæç»è¿æ®µä»£ç æ¯æ£ç¡®çï¼æç
§æä»¬ç¼åè¿ä¸ªå½æ°çæ¹å¼ï¼æå¯è½ä¸ä¸ªçº¿ç¨éå°I/Oé误ï¼å¯¼è´process_files_in_parallelå¨å
¶ä»çº¿ç¨å®æä¹åå°±æåéåºãè¿æ ·å线ç¨å¯è½ä¼å¨ä¸»çº¿ç¨éæ¾glossaryä¹åè¿å°è¯ä½¿ç¨å®ãè¿ä¼äº§çç«ææ¡ä»¶ï¼å¦æä¸»çº¿ç¨å
宿ï¼å°±ä¼å¯¼è´æªå®ä¹è¡ä¸ºãRustä¸å
许åºç°è¿ç§æ
åµã
çèµ·æ¥spawnç设计è¿äºå®½æ³ï¼ä¸æ¯æè·¨çº¿ç¨å
±äº«å¼ç¨ãå®é
ä¸ï¼æä»¬å¨ âçªåæææçéå
â ä¸å·²ç»éå°è¿ç±»ä¼¼çæ
åµãå¨é£éï¼æä»¬çè§£å³æ¹æ¡æ¯ä½¿ç¨moveéå
å°æ°æ®çæææè½¬ç§»å°æ°çº¿ç¨ãä½å¨è¿éè¿ç§æ¹æ³è¡ä¸éï¼å 为æä»¬æå¤ä¸ªçº¿ç¨é½éè¦ä½¿ç¨ç¸åçæ°æ®ãä¸ä¸ªå®å
¨çæ¿ä»£æ¹æ³æ¯ä¸ºæ¯ä¸ªçº¿ç¨å
éæ´ä¸ªæ¯è¯è¡¨ï¼ä½ç±äºæ¯è¯è¡¨å¾å¤§ï¼æä»¬å¸æé¿å
è¿ç§åæ³ã幸è¿çæ¯ï¼æ ååºæä¾äºå¦ä¸ç§æ¹å¼ï¼ååå¼ç¨è®¡æ°ã
æä»¬å¨ âRcåArcï¼å
±äº«æææâ ä¸ä»ç»è¿Arcãç°å¨æ¯æ¶å使ç¨å®äºï¼
use std::sync::Arc;
fn process_files_in_parallel(filenames: Vec<String>,
glossary: Arc<GigabyteMap>)
-> io::Result<()>
{
...
for worklist in worklists {
// è¿ä¸ª.clone()è°ç¨åªä¼å
éArcå¹¶å¢å å¼ç¨è®¡æ°ï¼ä¸ä¼å
éGigabyteMapã
let glossary_for_child = glossary.clone();
thread_handles.push(
spawn(move || process_files(worklist,
&glossary_for_child))
);
}
...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
æä»¬ä¿®æ¹äºglossaryçç±»åï¼ä¸ºäºå¹¶è¡è¿è¡åæï¼è°ç¨è
å¿
é¡»ä¼ å
¥ä¸ä¸ªArc<GigabyteMap>ï¼è¿æ¯ä¸ä¸ªæå已移å¨å°å ä¸çGigabyteMapçæºè½æéï¼å¯ä»¥éè¿Arc::new(giga_map)æ¥å建ã
彿们è°ç¨glossary.clone()æ¶ï¼æä»¬åªæ¯å¤å¶äºArcæºè½æéï¼è䏿¯æ´ä¸ªGigabyteMapãè¿ç¸å½äºå¢å äºå¼ç¨è®¡æ°ã
éè¿è¿ä¸ªä¿®æ¹ï¼ç¨åºå¯ä»¥ç¼è¯å¹¶è¿è¡ï¼å 为å®ä¸åä¾èµäºå¼ç¨ççå½å¨æãåªè¦æä»»ä½çº¿ç¨ææArc<GigabyteMap>ï¼å®å°±ä¼ä½¿GigabyteMapä¿æåæ´»ï¼å³ä½¿ç¶çº¿ç¨æåéåºä¹æ²¡é®é¢ãèä¸ä¸ä¼æä»»ä½æ°æ®ç«æï¼å 为Arcä¸çæ°æ®æ¯ä¸å¯åçã
# Rayon
æ ååºä¸çspawn彿°æ¯ä¸ä¸ªéè¦çåºç¡å½æ°ï¼ä½å®å¹¶éä¸é¨ä¸ºå治并è¡è®¾è®¡ãå¨å®ä¹ä¸ï¼å·²ç»æå»ºäºæ´éååæ²»å¹¶è¡çAPIãä¾å¦ï¼å¨ç¬¬2ç« ä¸ï¼æä»¬ä½¿ç¨äºCrossbeamåºå°ä¸äºå·¥ä½åé
å°å
«ä¸ªçº¿ç¨ä¸ã
Crossbeamçä½ç¨å线ç¨ï¼scoped threadsï¼å¯¹å治并è¡çæ¯æé常èªç¶ã
ç±Niko MatsakisåJosh Stoneå¼åçRayonåºæ¯å¦ä¸ä¸ªä¾åã宿ä¾äºä¸¤ç§å¹¶åè¿è¡ä»»å¡çæ¹å¼ï¼
use rayon::prelude::*;
// "å¹¶è¡æ§è¡ä¸¤ä¸ªä»»å¡"
let (v1, v2) = rayon::join(fn1, fn2);
// "å¹¶è¡æ§è¡N个任å¡"
giant_vector.par_iter().for_each(|value| {
do_thing_with_value(value);
});
2
3
4
5
6
7
8
9
rayon::join(fn1, fn2)ä¼åæ¶è°ç¨è¿ä¸¤ä¸ªå½æ°å¹¶è¿åå®ä»¬çç»æã.par_iter()æ¹æ³ä¼å建ä¸ä¸ªParallelIteratorï¼å®æ¥æmapãfilterçæ¹æ³ï¼ä¸RustçIteratorå¾ç¸ä¼¼ãå¨è¿ä¸¤ç§æ
åµä¸ï¼Rayonä¼å°½å¯è½å°ä½¿ç¨å®èªå·±çå·¥ä½çº¿ç¨æ± æ¥åé
å·¥ä½ãä½ åªéåè¯Rayonåªäºä»»å¡å¯ä»¥å¹¶è¡å®æï¼Rayonä¼ç®¡ç线ç¨å¹¶å°½å¯è½ä¼åå°åé
å·¥ä½ã
å¾19 - 3ä¸ç示æå¾å±ç¤ºäºçè§£giant_vector.par_iter().for_each(...)è°ç¨çä¸¤ç§æ¹å¼ã(a) Rayonçè¡ä¸ºå°±å¥½å为åéä¸çæ¯ä¸ªå
ç´ é½å建äºä¸ä¸ªçº¿ç¨ã(b) å¨å¹åï¼Rayon为æ¯ä¸ªCPUæ ¸å¿åé
ä¸ä¸ªå·¥ä½çº¿ç¨ï¼è¿æ ·æçæ´é«ãè¿ä¸ªå·¥ä½çº¿ç¨æ± ç±ç¨åºä¸çææçº¿ç¨å
±äº«ãå½åæ¶ææ°å个任å¡å°æ¥æ¶ï¼Rayonä¼å¯¹å·¥ä½è¿è¡ååã
å¾19 - 3. Rayonå¨ç论åå®è·µä¸çæ
åµ
ä¸é¢æ¯ä½¿ç¨Rayonå®ç°çprocess_files_in_parallelçæ¬ï¼è¿éçprocess_file彿°æ¥åçåæ°æ¯&strï¼è䏿¯Vec<String>ï¼
use rayon::prelude::*;
fn process_files_in_parallel(filenames: Vec<String>, glossary: &GigabyteMap)
-> io::Result<()>
{
filenames.par_iter()
.map(|filename| process_file(filename, glossary))
.reduce_with(|r1, r2| {
if r1.is_err() { r1 } else { r2 }
})
.unwrap_or(Ok(()))
}
2
3
4
5
6
7
8
9
10
11
12
è¿æ®µä»£ç æ¯ä½¿ç¨std::thread::spawnççæ¬æ´ç®çï¼ä¹æ´ç®åãæä»¬éè¡åæä¸ä¸ï¼
- é¦å
ï¼æä»¬ä½¿ç¨
filenames.par_iter()å建ä¸ä¸ªå¹¶è¡è¿ä»£å¨ã - æ¥ç使ç¨
.map()对æ¯ä¸ªæä»¶åè°ç¨process_fileãè¿ä¼çæä¸ä¸ªå å«ä¸ç³»åio::Result<()>å¼çå¹¶è¡è¿ä»£å¨ã - ç¶å使ç¨
.reduce_with()æ¥åå¹¶ç»æãå¨è¿éï¼å¦ææéè¯¯ï¼æä»¬ä¿ç第ä¸ä¸ªé误ï¼ä¸¢å¼å ¶ä»é误ã妿æä»¬æ³è¦ç´¯ç§¯ææå°ææé误ï¼ä¹å¯ä»¥å¨è¿éå®ç°ãå½ä½ ä¼ éç».map()çéå 卿忶è¿åä¸ä¸ªæç¨ç弿¶ï¼.reduce_with()æ¹æ³ä¹å¾æç¨ãè¿æ¶ï¼ä½ å¯ä»¥ç».reduce_with()ä¼ éä¸ä¸ªéå ï¼ç¨äºå并两个æåçç»æã reduce_withè¿åä¸ä¸ªOptionï¼åªæå½filenamesä¸ºç©ºæ¶æä¸ºNoneãæä»¬ä½¿ç¨Optionç.unwrap_or()æ¹æ³ï¼å¨è¿ç§æ åµä¸å°ç»æè®¾ä¸ºOk(())ã
å¨å¹åï¼Rayon使ç¨ä¸ç§ç§°ä¸ºå·¥ä½çªåï¼work - stealingï¼çææ¯å¨å个线ç¨ä¹é´å¨æå¹³è¡¡å·¥ä½è´è½½ãé常ï¼å®å¨è®©ææCPUä¿æå¿ç¢æ¹é¢ï¼æ¯æä»¬å¨ âspawnåjoinâ 䏿卿åååå·¥ä½çæææ´å¥½ã
å¦å¤ï¼Rayonæ¯æè·¨çº¿ç¨å
±äº«å¼ç¨ãå¨å¹åè¿è¡çä»»ä½å¹¶è¡å¤çï¼å¨reduce_withè¿åæ¶é½è½ä¿è¯å®æãè¿å°±è§£éäºä¸ºä»ä¹æä»¬å¯ä»¥å°glossaryä¼ éç»process_fileï¼å³ä½¿è¿ä¸ªéå
ä¼å¨å¤ä¸ªçº¿ç¨ä¸è¢«è°ç¨ã
ï¼é¡ºä¾¿è¯´ä¸å¥ï¼æä»¬ä½¿ç¨äºmapæ¹æ³åreduceæ¹æ³å¹¶éå¶ç¶ãç±è°·æåApache Hadoopæ¨å¹¿çMapReduceç¼ç¨æ¨¡åä¸åæ²»å¹¶è¡æå¾å¤å
±åä¹å¤ãå®å¯ä»¥è¢«ç使¯ä¸ç§æ¥è¯¢åå¸å¼æ°æ®çåæ²»å¹¶è¡æ¹æ³ãï¼
# å顾æ¼å¾·å¸æ´ç¹éåç»å¶
å¨ç¬¬2ç« ä¸ï¼æä»¬ä½¿ç¨åæ²»å¹¶åæ¥ç»å¶æ¼å¾·å¸æ´ç¹éåãè¿ä½¿å¾æ¸²æé度æé«äºååï¼è½ç¶ä»¤äººå°è±¡æ·±å»ï¼ä½èèå°æä»¬è®©ç¨åºå¯å¨äºå «ä¸ªå·¥ä½çº¿ç¨å¹¶å¨ä¸ä¸ªå «æ ¸å¿çæºå¨ä¸è¿è¡ï¼å ¶å®è¿å¯ä»¥æ´å¿«ï¼
é®é¢å¨äºæä»¬æ²¡æååå°åé å·¥ä½è´è½½ã计ç®å¾åçä¸ä¸ªåç´ ç¸å½äºè¿è¡ä¸ä¸ªå¾ªç¯ï¼åè§ âæ¼å¾·å¸æ´ç¹éåçå®é åçâï¼ãç»æåç°ï¼å¾å䏿µ ç°è²é¨åç循ç¯å¾å¿«å°±ä¼éåºï¼æ¸²æèµ·æ¥æ¯é»è²é¨åè¦å¿«å¾å¤ï¼é»è²é¨åç循ç¯éè¦å®æ´è¿è¡255次è¿ä»£ãæä»¥ï¼å°½ç®¡æä»¬å°å¾ååºååå为大å°ç¸ççæ°´å¹³æ¡å¸¦ï¼ä½å®é ä¸å建äºä¸åè¡¡çå·¥ä½è´è½½ï¼å¦å¾19 - 4æç¤ºã
å¾19 - 4. æ¼å¾·å¸æ´ç¹ç¨åºä¸ä¸åè¡¡çå·¥ä½åé
使ç¨Rayonå¾å®¹æè§£å³è¿ä¸ªé®é¢ãæä»¬å¯ä»¥ä¸ºè¾åºå¾åçæ¯ä¸è¡åç´ å¯å¨ä¸ä¸ªå¹¶è¡ä»»å¡ãè¿æ ·ä¼å建å ç¾ä¸ªä»»å¡ï¼Rayonå¯ä»¥å°è¿äºä»»å¡åé
å°å个线ç¨ä¸ãç±äºéç¨äºå·¥ä½çªåææ¯ï¼ä»»å¡å¤§å°ä¸å乿²¡å
³ç³»ãRayonä¼å¨è¿è¡è¿ç¨ä¸å¹³è¡¡å·¥ä½è´è½½ã
ä¸é¢æ¯ä»£ç ã第ä¸è¡åæåä¸è¡æ¯æä»¬å¨ âä¸ä¸ªå¹¶åçæ¼å¾·å¸æ´ç¹ç¨åºâ ä¸å±ç¤ºçmain彿°çä¸é¨åï¼ä½æä»¬ä¿®æ¹äºä¸é´ç渲æä»£ç ï¼
let mut pixels = vec![0; bounds.0 * bounds.1];
// 对`pixels`ææ°´å¹³æ¡å¸¦è¿è¡åççä½ç¨å
{
let bands: Vec<(usize, &mut [u8])> = pixels
.chunks_mut(bounds.0)
.enumerate()
.collect();
bands.into_par_iter()
.for_each(|(i, band)| {
let top = i;
let band_bounds = (bounds.0, 1);
let band_upper_left = pixel_to_point(bounds, (0, top), upper_left, lower_right);
let band_lower_right = pixel_to_point(bounds, (bounds.0, top + 1), upper_left, lower_right);
render(band, band_bounds, band_upper_left, band_lower_right);
});
}
write_image(&args[1], &pixels, bounds).expect("error writing PNG file");
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
é¦å
ï¼æä»¬å建bandsï¼è¿æ¯ä¸ä¸ªä»»å¡éåï¼æä»¬å°æå®ä¼ éç»Rayonãæ¯ä¸ªä»»å¡åªæ¯ä¸ä¸ª(usize, &mut [u8])ç±»åçå
ç»ï¼è¡å·ï¼å 为计ç®éè¦è¿ä¸ªä¿¡æ¯ï¼åè¦å¡«å
çåç´ åçãæä»¬ä½¿ç¨chunks_mutæ¹æ³å°å¾åç¼å²åºæè¡åå²ï¼ä½¿ç¨enumerate为æ¯ä¸è¡éä¸ä¸ä¸ªè¡å·ï¼å使ç¨collectå°ææçè¡å· - åç对æ¶éå°ä¸ä¸ªåéä¸ï¼æä»¬éè¦ä¸ä¸ªåéï¼å 为Rayonä»
仿°ç»ååéå建并è¡è¿ä»£å¨ï¼ã
æ¥ä¸æ¥ï¼æä»¬å°bands转æ¢ä¸ºå¹¶è¡è¿ä»£å¨ï¼å¹¶ä½¿ç¨.for_each()æ¹æ³åè¯Rayonæä»¬æ³è¦å®æçå·¥ä½ã
å 为æä»¬ä½¿ç¨äºRayonï¼æä»¥å¿
é¡»å¨main.rs䏿·»å è¿ä¸è¡ï¼
use rayon::prelude::*;
å¹¶å¨Cargo.toml䏿·»å ï¼
[dependencies]
rayon = "1"
2
éè¿è¿äºä¿®æ¹ï¼è¿ä¸ªç¨åºç°å¨å¨ä¸ä¸ª8æ ¸å¿çæºå¨ä¸å¯ä»¥å©ç¨å¤§çº¦7.75ä¸ªæ ¸å¿ãæ¯æä»¬ä¹åæå¨åå工使¶å¿«äº75%ãèä¸ä»£ç 乿´ç®çäºä¸äºï¼è¿ä½ç°äºè®©åºæ¥å®æå·¥ä½ï¼å·¥ä½åé ï¼è䏿¯æä»¬èªå·±å»åç好å¤ã
# éé
é鿝ä¸ç§ç¨äºå¨ä¸å线ç¨é´ååä¼ éå¼çæºå¶ãæ¢å¥è¯è¯´ï¼å®æ¯ä¸ä¸ªçº¿ç¨å®å ¨çéåãå¾19 - 5å±ç¤ºäºééçä½¿ç¨æ¹å¼ã宿ç¹åUnix管éï¼ä¸ç«¯ç¨äºåéæ°æ®ï¼å¦ä¸ç«¯ç¨äºæ¥æ¶æ°æ®ãè¿ä¸¤ç«¯é常ç±ä¸¤ä¸ªä¸åççº¿ç¨ææãä¸è¿ï¼Unix管éç¨äºåéåèï¼èRustä¸çééç¨äºåéRustå¼ã
sender.send(item)å°åä¸ªå¼æ¾å
¥ééï¼receiver.recv()åä»ééä¸ååºä¸ä¸ªå¼ãå¼çæææä¼ä»åé线ç¨è½¬ç§»å°æ¥æ¶çº¿ç¨ã妿éé为空ï¼receiver.recv()ä¼é»å¡ï¼ç´å°æå¼è¢«åéè¿æ¥ã
)
å¾19 - 5. ç¨äºä¼ éStringçééï¼å符串msgçæææä»çº¿ç¨1转移å°çº¿ç¨2
éè¿ééï¼çº¿ç¨å¯ä»¥éè¿ç¸äºä¼ éå¼è¿è¡éä¿¡ãè¿æ¯ä¸ç§çº¿ç¨é´åä½çç®åæ¹å¼ï¼æ é使ç¨éæå ±äº«å åã
è¿å¹¶ä¸æ¯ä¸ç§æ°ææ¯ãErlangå·²ç»æç¬ç«çè¿ç¨åæ¶æ¯ä¼ éæºå¶é¿è¾¾30å¹´ä¹ä¹ ãUnix管éä¹åå¨äºè¿50å¹´ãæä»¬é常认为管éæä¾äºçµæ´»æ§åå¯ç»åæ§ï¼èéå¹¶ååè½ï¼ä½å®é ä¸ï¼å®å ¼å ·è¿äºç¹æ§ãå¾19 - 6å±ç¤ºäºä¸ä¸ªUnix管éç示ä¾ãå®é ä¸ï¼è¿ä¸ä¸ªç¨åºå®å ¨å¯ä»¥åæ¶å·¥ä½ã
Rusté鿝Unixç®¡éæ´å¿«ãåéä¸ä¸ªå¼æ¶æ¯ç§»å¨è¯¥å¼è䏿¯å¤å¶å®ï¼å³ä½¿ç§»å¨å 嫿°å åèæ°æ®çæ°æ®ç»æï¼è¿ç§ç§»å¨æä½ä¹å¾å¿«ã
å¾19 - 6. Unix管éçæ§è¡è¿ç¨
# åéå¼
卿¥ä¸æ¥çå 个é¨åä¸ï¼æä»¬å°ä½¿ç¨ééæå»ºä¸ä¸ªå¹¶åç¨åºï¼ç¨äºå建åæç´¢å¼ï¼è¿æ¯æç´¢å¼æçå ³é®ç»æé¨åä¹ä¸ãæ¯ä¸ªæç´¢å¼æé½é对ç¹å®çææ¡£éåè¿è¡å·¥ä½ãåæç´¢å¼æ¯ä¸ä¸ªæ°æ®åºï¼ç¨äºè®°å½åªäºåè¯åºç°å¨åªäºææ¡£ä¸ã
æä»¬å°å±ç¤ºä»£ç ä¸ä¸çº¿ç¨åééç¸å ³çé¨åã宿´çç¨åºå¾çï¼æ»å ±å¤§çº¦ä¸åè¡ä»£ç ã
æä»¬çç¨åºç»ææ¯ä¸ä¸ªæµæ°´çº¿ï¼å¦å¾19 - 7æç¤ºãæµæ°´çº¿åªæ¯ä½¿ç¨ééçä¼å¤æ¹å¼ä¹ä¸ï¼å颿们è¿ä¼è®¨è®ºå ¶ä»å ç§ç¨æ³ï¼ä½å®æ¯å°å¹¶åå¼å ¥ç°æå线ç¨ç¨åºçä¸ç§ç´æ¥æ¹å¼ã
æä»¬æ»å
±ä¼ä½¿ç¨äºä¸ªçº¿ç¨ï¼æ¯ä¸ªçº¿ç¨æ§è¡ä¸åçä»»å¡ãå¨ç¨åºçæ´ä¸ªçå½å¨æä¸ï¼æ¯ä¸ªçº¿ç¨é½ä¼æç»äº§çè¾åºãä¾å¦ï¼ç¬¬ä¸ä¸ªçº¿ç¨ç任塿¯å°ç£çä¸çæºææ¡£é个读åå°å
åä¸ï¼æä»¬è®©ä¸ä¸ªçº¿ç¨æ¥åè¿ä»¶äºï¼æ¯å 为è¿éæä»¬è¦ç¼åå°½å¯è½ç®åç代ç ï¼ä½¿ç¨fs::read_to_stringï¼è¿æ¯ä¸ä¸ªé»å¡å¼APIãæä»¬ä¸å¸æå¨ç£ç工使¶CPUå¤äºç©ºé²ç¶æï¼ãè¿ä¸ªé¶æ®µçè¾åºæ¯æ¯ä¸ªææ¡£å¯¹åºçä¸ä¸ªé¿åç¬¦ä¸²ï¼æä»¥è¿ä¸ªçº¿ç¨éè¿ä¸ä¸ªç¨äºä¼ éå符串çééä¸ä¸ä¸ä¸ªçº¿ç¨ç¸è¿ã
å¾19 - 7. ç´¢å¼æå»ºæµæ°´çº¿ï¼ç®å¤´è¡¨ç¤ºéè¿ééä»ä¸ä¸ªçº¿ç¨åéå°å¦ä¸ä¸ªçº¿ç¨çå¼ï¼æªå±ç¤ºç£çI/O)
æä»¬çç¨åºå°ä»å¯å¨è¯»åæä»¶ç线ç¨å¼å§ãå设documentsæ¯ä¸ä¸ªVec<PathBuf>ç±»åçåéï¼å
嫿件åãå¯å¨æä»¶è¯»å线ç¨ç代ç å¦ä¸ï¼
use std::{fs, thread};
use std::sync::mpsc;
let (sender, receiver) = mpsc::channel();
let handle = thread::spawn(move || {
for filename in documents {
let text = fs::read_to_string(filename)?;
if sender.send(text).is_err() {
break;
}
}
Ok(())
});
2
3
4
5
6
7
8
9
10
11
12
13
é鿝std::sync::mpsc模åçä¸é¨åãæä»¬ç¨åä¼è§£éè¿ä¸ªåç§°çå«ä¹ï¼é¦å
æ¥çè¿æ®µä»£ç çå·¥ä½åçãæä»¬é¦å
å建ä¸ä¸ªééï¼
let (sender, receiver) = mpsc::channel();
channel彿°è¿åä¸å¯¹å¼ï¼ä¸ä¸ªåé端åä¸ä¸ªæ¥æ¶ç«¯ãåºå±çéåæ°æ®ç»ææ¯æ ååºæªå
¬å¼çå®ç°ç»èã
é鿝æç±»åçãæä»¬æç®ç¨è¿ä¸ªééåéæ¯ä¸ªæä»¶çææ¬å
å®¹ï¼æä»¥æä»¬æä¸ä¸ªç±»å为Sender<String>çåé端åä¸ä¸ªç±»å为Receiver<String>çæ¥æ¶ç«¯ãæä»¬æ¬å¯ä»¥éè¿mpsc::channel::<String>()æ¾å¼æå®è¿æ¯ä¸ä¸ªç¨äºä¼ éå符串çééï¼ä½è¿éæä»¬è®©Rustçç±»åæ¨ææ¥ç¡®å®ã
let handle = thread::spawn(move || {
åä¹å䏿 ·ï¼æä»¬ä½¿ç¨std::thread::spawnå¯å¨ä¸ä¸ªçº¿ç¨ãéè¿è¿ä¸ªmoveéå
ï¼senderï¼èéreceiverï¼çæææè¢«è½¬ç§»å°æ°çº¿ç¨ä¸ã
æ¥ä¸æ¥çå è¡ä»£ç åªæ¯ä»ç£ç读åæä»¶ï¼
for filename in documents {
let text = fs::read_to_string(filename)?;
2
æå读åæä»¶åï¼æä»¬å°æä»¶çææ¬å 容åéå°ééä¸ï¼
if sender.send(text).is_err() {
break;
}
2
3
sender.send(text)å°textè¿ä¸ªå¼ç§»å¨å°ééä¸ãæç»ï¼å®ä¼å次被移å¨å°æ¥æ¶è¯¥å¼ç线ç¨ä¸ãæ 论textå
å«10è¡ææ¬è¿æ¯10å
åèçæ°æ®ï¼è¿ä¸ªæä½åªå¤å¶ä¸ä¸ªæºå¨åï¼Stringç»æä½ç大å°ï¼ï¼ç¸åºçreceiver.recv()è°ç¨ä¹åªä¼å¤å¶ä¸ä¸ªæºå¨åãsendårecvæ¹æ³é½è¿åResultï¼ä½åªæå¨ééçå¦ä¸ç«¯è¢«ä¸¢å¼æ¶ï¼è¿äºæ¹æ³æä¼å¤±è´¥ã妿Receiver被丢å¼ï¼sendè°ç¨ä¼å¤±è´¥ï¼å 为å¦åè¿ä¸ªå¼ä¼æ°¸è¿çå¨ééä¸ï¼æ²¡æReceiverï¼ä»»ä½çº¿ç¨é½æ æ³æ¥æ¶å®ãåæ ·ï¼å¦æéé䏿²¡æçå¾
çå¼ä¸Sender被丢å¼ï¼recvè°ç¨ä¹ä¼å¤±è´¥ï¼å 为å¦årecv伿°¸è¿çå¾
ï¼æ²¡æSenderï¼ä»»ä½çº¿ç¨é½æ æ³åéä¸ä¸ä¸ªå¼ã丢å¼ééçä¸ç«¯æ¯æ£å¸¸ç âææâ æ¹å¼ï¼å³å½ä½ 使ç¨å®ééåå
³éè¿æ¥ã
卿们ç代ç ä¸ï¼sender.send(text)åªæå¨æ¥æ¶ç«¯æå¨çº¿ç¨æåéåºæ¶æä¼å¤±è´¥ãè¿å¨ä½¿ç¨ééç代ç ä¸å¾å¸¸è§ãæ 论è¿ç§æ
嵿¯ææä¸ºä¹è¿æ¯ç±é误导è´çï¼å¯¹äºæä»¬ç读åçº¿ç¨æ¥è¯´ï¼å®éå°å
³éèªèº«é½æ¯å¯ä»¥æ¥åçã
å½åçè¿ç§æ
åµï¼æè
线ç¨è¯»å®ææææ¡£åï¼å®ä¼è¿åOk(())ï¼
Ok(())
});
2
注æï¼è¿ä¸ªéå
è¿åä¸ä¸ªResultãå¦æçº¿ç¨éå°I/Oé误ï¼å®ä¼ç«å³éåºï¼å¹¶ä¸é误ä¼åå¨å¨çº¿ç¨çJoinHandleä¸ã
å½ç¶ï¼åå
¶ä»ç¼ç¨è¯è¨ä¸æ ·ï¼å¨é误å¤çæ¹é¢Rust乿å¾å¤å
¶ä»éæ©ãåçé误æ¶ï¼æä»¬å¯ä»¥ä½¿ç¨println!æå°é误信æ¯ï¼ç¶åç»§ç»å¤çä¸ä¸ä¸ªæä»¶ãæä»¬ä¹å¯ä»¥éè¿ç¨äºä¼ è¾æ°æ®çåä¸ä¸ªééä¼ éé误ï¼ä½¿å
¶æä¸ºä¸ä¸ªä¼ éResultçééï¼æè
ä¸é¨å建第äºä¸ªééæ¥ä¼ éé误ãæä»¬è¿ééæ©çæ¹æ³æ¢ç®æ´åå¯é ï¼æä»¬å¯ä»¥ä½¿ç¨?æä½ç¬¦ï¼è¿æ ·å°±æ²¡æä¸å æ ·æ¿ä»£ç ï¼çè³ä¸åå¨Javaä¸é£æ ·éè¦æ¾å¼çtry/catchè¯å¥ï¼ä½é误ä¹ä¸ä¼è¢«ææå¿½ç¥ã
ä¸ºäºæ¹ä¾¿ï¼æä»¬çç¨åºå°ææè¿äºä»£ç å°è£
å¨ä¸ä¸ªå½æ°ä¸ï¼è¯¥å½æ°è¿åreceiverï¼æä»¬è¿æªä½¿ç¨å®ï¼åæ°çº¿ç¨çJoinHandleï¼
fn start_file_reader_thread(documents: Vec<PathBuf>)
-> (mpsc::Receiver<String>,
thread::JoinHandle<io::Result<()>>)
{
let (sender, receiver) = mpsc::channel();
let handle = thread::spawn(move || {
...
});
(receiver, handle)
}
2
3
4
5
6
7
8
9
10
注æï¼è¿ä¸ªå½æ°å¯å¨æ°çº¿ç¨åä¼ç«å³è¿åãæä»¬ä¼ä¸ºæµæ°´çº¿çæ¯ä¸ªé¶æ®µç¼åä¸ä¸ªè¿æ ·ç彿°ã
# æ¥æ¶å¼
ç°å¨æä»¬æä¸ä¸ªçº¿ç¨å¨è¿è¡ä¸ä¸ªåéå¼ç循ç¯ãæä»¬å¯ä»¥å¯å¨ç¬¬äºä¸ªçº¿ç¨ï¼è¯¥çº¿ç¨è¿è¡ä¸ä¸ªè°ç¨receiver.recv()ç循ç¯ï¼
while let Ok(text) = receiver.recv() {
do_something_with(text);
}
2
3
ä¸è¿ï¼Receiveræ¯å¯è¿ä»£çï¼æä»¥æä¸ç§æ´ç®æ´çåæ³ï¼
for text in receiver {
do_something_with(text);
}
2
3
è¿ä¸¤ä¸ªå¾ªç¯æ¯çæçãä¸ç®¡æä»¬éç¨åªç§åæ³ï¼å¦æå½æ§å¶æµå°è¾¾å¾ªç¯é¡¶é¨æ¶ééæ°å¥½ä¸ºç©ºï¼æ¥æ¶çº¿ç¨å°é»å¡ï¼ç´å°å
¶ä»çº¿ç¨åéä¸ä¸ªå¼ãå½éé为空ä¸Senderå·²è¢«ä¸¢å¼æ¶ï¼å¾ªç¯å°æ£å¸¸éåºã卿们çç¨åºä¸ï¼å½è¯»å线ç¨éåºæ¶ï¼è¿ç§æ
åµä¼èªç¶åçã该线ç¨è¿è¡çéå
æ¥æåésenderï¼å½éå
éåºæ¶ï¼senderå°±ä¼è¢«ä¸¢å¼ã
ç°å¨æä»¬å¯ä»¥ç¼åæµæ°´çº¿ç¬¬äºé¶æ®µç代ç ï¼
fn start_file_indexing_thread(texts: mpsc::Receiver<String>)
-> (mpsc::Receiver<InMemoryIndex>, thread::JoinHandle<()>)
{
let (sender, receiver) = mpsc::channel();
let handle = thread::spawn(move || {
for (doc_id, text) in texts.into_iter().enumerate() {
let index =
InMemoryIndex::from_single_document(doc_id, text);
if sender.send(index).is_err() {
break;
}
}
});
(receiver, handle)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
è¿ä¸ªå½æ°å¯å¨ä¸ä¸ªçº¿ç¨ï¼è¯¥çº¿ç¨ä»ä¸ä¸ªééï¼textsï¼æ¥æ¶Stringå¼ï¼å¹¶å°InMemoryIndexå¼åéå°å¦ä¸ä¸ªééï¼sender/receiverï¼ãè¿ä¸ªçº¿ç¨ç任塿¯å°ç¬¬ä¸é¶æ®µå è½½çæ¯ä¸ªæä»¶è½¬æ¢ä¸ºä¸ä¸ªå°åçãå
åä¸çåæä»¶åæç´¢å¼ã
该线ç¨ç主循ç¯å¾ç®åãå¯¹ææ¡£è¿è¡ç´¢å¼çææå·¥ä½é½ç±InMemoryIndex::from_single_document彿°å®æãæä»¬è¿éä¸å±ç¤ºå®çæºä»£ç ï¼ä½å®ä¼å¨åè¯è¾¹çå¤åå²è¾å
¥å符串ï¼ç¶åçæä¸ä¸ªä»åè¯å°ä½ç½®åè¡¨çæ å°ã
è¿ä¸ªé¶æ®µä¸æ§è¡I/Oæä½ï¼æä»¥å®æ éå¤çio::Errorãå®è¿åç䏿¯io::Result<()>ï¼èæ¯()ã
# è¿è¡æµæ°´çº¿
å©ä¸çä¸ä¸ªé¶æ®µå¨è®¾è®¡ä¸ç±»ä¼¼ãæ¯ä¸ªé¶æ®µé½ä½¿ç¨åä¸ä¸ªé¶æ®µå建çReceiverãæä»¬æµæ°´çº¿å
¶ä½é¨åçç®æ æ¯å°ææå°ç´¢å¼åå¹¶å°ç£çä¸çä¸ä¸ªå¤§åç´¢å¼æä»¶ä¸ãæä»¬åç°å®ç°è¿ä¸ç®æ æå¿«çæ¹æ³éè¦ä¸ä¸ªé¶æ®µãæä»¬è¿éä¸å±ç¤ºä»£ç ï¼åªç»åºè¿ä¸ä¸ªå½æ°çç±»åç¾åã宿´çæºä»£ç å¯ä»¥å¨ç½ä¸æ¾å° ã
é¦å ï¼æä»¬å¨å åä¸åå¹¶ç´¢å¼ï¼ç´å°å®ä»¬åå¾é¾ä»¥å¤çï¼é¶æ®µ3ï¼ï¼
fn start_in_memory_merge_thread(file_indexes:
mpsc::Receiver<InMemoryIndex>)
-> (mpsc::Receiver<InMemoryIndex>, thread::JoinHandle<()>)
2
3
ç¶åï¼æä»¬å°è¿äºå¤§åç´¢å¼åå ¥ç£çï¼é¶æ®µ4ï¼ï¼
fn start_index_writer_thread(big_indexes: mpsc::Receiver<InMemoryIndex>,
output_dir: &Path)
-> (mpsc::Receiver<PathBuf>,
thread::JoinHandle<io::Result<()>>)
2
3
4
æåï¼å¦ææä»¬æå¤ä¸ªå¤§åæä»¶ï¼æä»¬ä½¿ç¨åºäºæä»¶çåå¹¶ç®æ³å°å®ä»¬åå¹¶ï¼é¶æ®µ5ï¼ï¼
fn merge_index_files(files: mpsc::Receiver<PathBuf>, output_dir: &Path)
-> io::Result<()>
2
æåè¿ä¸ªé¶æ®µä¸è¿åReceiverï¼å ä¸ºå®æ¯æµæ°´çº¿çç»ç¹ãå®å¨ç£çä¸çæä¸ä¸ªåä¸çè¾åºæä»¶ãå®ä¹ä¸è¿åJoinHandleï¼å 为æä»¬æ²¡æä¸ºè¿ä¸ªé¶æ®µå¯å¨çº¿ç¨ï¼å·¥ä½å¨è°ç¨è
线ç¨ä¸å®æã
ç°å¨æ¥çå¯å¨çº¿ç¨å¹¶æ£æ¥é误ç代ç ï¼
fn run_pipeline(documents: Vec<PathBuf>, output_dir: PathBuf)
-> io::Result<()>
{
// å¯å¨æµæ°´çº¿çææäºä¸ªé¶æ®µã
let (texts, h1) = start_file_reader_thread(documents);
let (pints, h2) = start_file_indexing_thread(texts);
let (gallons, h3) = start_in_memory_merge_thread(pints);
let (files, h4) = start_index_writer_thread(gallons, &output_dir);
let result = merge_index_files(files, &output_dir);
// çå¾
线ç¨å®æï¼æè·å®ä»¬éå°çä»»ä½é误ã
let r1 = h1.join().unwrap();
h2.join().unwrap();
h3.join().unwrap();
let r4 = h4.join().unwrap();
// 妿æé误ï¼è¿åéå°ç第ä¸ä¸ªé误ã
// ï¼ç¢°å·§çæ¯ï¼h2åh3ä¸ä¼å¤±è´¥ï¼è¿äºçº¿ç¨åªæ¯è¿è¡çº¯å
åæ°æ®å¤çãï¼
r1?;
r4?;
result
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
åä¹å䏿 ·ï¼æä»¬ä½¿ç¨.join().unwrap()å°å线ç¨ä¸çææ
ï¼panicï¼æ¾å¼å°ä¼ æå°ä¸»çº¿ç¨ã
è¿éå¯ä¸ä¸å寻常çå°æ¹æ¯ï¼æä»¬æ²¡æç«å³ä½¿ç¨?ï¼èæ¯å
ä¿çio::Resultå¼ï¼ç´å°æä»¬çå¾
ææå个线ç¨é½å®æã
è¿ä¸ªæµæ°´çº¿æ¯çæçå线ç¨ç¨åºå¿«40%ã对äºä¸ä¸åçå·¥ä½æææ¥è¯´ï¼è¿è¿ä¸éï¼ä½ä¸æ¼å¾·å¸æ´ç¹ç¨åº675%çæéç¸æ¯ï¼å°±æ¾å¾å¾®ä¸è¶³éäºãæ¾ç¶ï¼æä»¬æ¢æ²¡æå åå©ç¨ç³»ç»çI/Oè½åï¼ä¹æ²¡æè®©ææCPUæ ¸å¿é½é¥±åè¿è¡ãè¿æ¯æä¹åäºå¢ï¼
æµæ°´çº¿å°±åå¶é å·¥åä¸çè£
é
çº¿ï¼æ§è½åéäºææ
¢é¶æ®µçååéã䏿¡å
¨æ°çãæªç»ä¼åçè£
é
线å¯è½ååä»¶çäº§ä¸æ ·æ
¢ï¼ä½è£
é
线å¨ç»è¿æé对æ§çä¼åå伿æ´å¥½ç表ç°ã卿们çä¾åä¸ï¼æµéç»æè¡¨æç¬¬äºé¶æ®µæ¯ç¶é¢ãæä»¬çç´¢å¼çº¿ç¨ä½¿ç¨äº.to_lowercase()å.is_alphanumeric()ï¼æä»¥å®è±è´¹äºå¤§éæ¶é´å¨Unicodeè¡¨ä¸æ¥æ¾ãç´¢å¼é¶æ®µä¸æ¸¸çå
¶ä»é¶æ®µå¤§é¨åæ¶é´é½å¨Receiver::recvä¸çå¾
è¾å
¥ã
è¿æå³çæä»¬åºè¯¥å¯ä»¥è®©ç¨åºè¿è¡å¾æ´å¿«ãéçæä»¬è§£å³è¿äºç¶é¢é®é¢ï¼å¹¶è¡åº¦å°ä¼æé«ãæ¢ç¶ä½ å·²ç»ç¥éå¦ä½ä½¿ç¨ééï¼å¹¶ä¸æä»¬çç¨åºç±ç¸äºç¬ç«ç代ç çæ®µç»æï¼é£ä¹å°±å¾å®¹ææ³å°è§£å³ç¬¬ä¸ä¸ªç¶é¢çæ¹æ³ãæä»¬å¯ä»¥åä¼åå ¶ä»ä»£ç 䏿 ·ï¼æå¨ä¼å第äºé¶æ®µç代ç ï¼å°å·¥ä½åè§£ä¸ºä¸¤ä¸ªææ´å¤é¶æ®µï¼æè åæ¶è¿è¡å¤ä¸ªæä»¶ç´¢å¼çº¿ç¨ã
# ééç¹æ§åæ§è½
std::sync::mpscä¸çmpsc代表 âå¤ç产è
ï¼åæ¶è´¹è
âï¼multiproducer, single-consumerï¼ï¼è¿ç®æ´å°æè¿°äºRustééææä¾çéä¿¡ç±»åã
æä»¬ç¤ºä¾ç¨åºä¸çééå°å¼ä»å个åéè ä¼ éå°åä¸ªæ¥æ¶è ãè¿æ¯ä¸ç§ç¸å½å¸¸è§çæ åµãä½Rustéé乿¯æå¤ä¸ªåéè ï¼ä¾å¦ï¼å½ä½ éè¦ä¸ä¸ªçº¿ç¨å¤çæ¥èªå¤ä¸ªå®¢æ·ç«¯çº¿ç¨çè¯·æ±æ¶ï¼å°±å¯ä»¥ä½¿ç¨è¿ç§ç¹æ§ï¼å¦å¾19 - 8æç¤ºã
å¾19 - 8. ä¸ä¸ªééæ¥æ¶æ¥èªå¤ä¸ªåéè
ç请æ±
Sender<T>å®ç°äºCloneç¹æ§ãè¦å建ä¸ä¸ªæå¤ä¸ªåéè
çééï¼åªéå建ä¸ä¸ªæ®éééï¼ç¶åæ ¹æ®éè¦å
éåéè
ãä½ å¯ä»¥å°æ¯ä¸ªSenderå¼ç§»å¨å°ä¸åç线ç¨ä¸ã
Receiver<T>ä¸è½è¢«å
éï¼æä»¥å¦æä½ éè¦å¤ä¸ªçº¿ç¨ä»åä¸ä¸ªé鿥æ¶å¼ï¼å°±éè¦ä½¿ç¨Mutexãæä»¬å°å¨æ¬ç« åé¢å±ç¤ºå¦ä½å®ç°ã
Rustééç»è¿äºç²¾å¿ä¼åãå½é¦æ¬¡å建ééæ¶ï¼Rust使ç¨ä¸ç§ç¹æ®ç â䏿¬¡æ§â éåå®ç°ãå¦æä½ åªéè¿ééåéä¸ä¸ªå¯¹è±¡ï¼å¼éæå°ãå¦æä½ åé第äºä¸ªå¼ï¼Rustä¼åæ¢å°å¦ä¸ç§éåå®ç°ãå®é
ä¸ï¼è¿æ¯ä¸ºäºé¿æä½¿ç¨ååå¤ï¼è®©ééå¨ä¼ è¾å¤§éå¼çåæ¶å°½éåå°åé
å¼éãå¦æä½ å
éäºSenderï¼Rustå¿
须使ç¨å¦ä¸ç§å®ç°ï¼è¿ç§å®ç°è½ç¡®ä¿å¨å¤ä¸ªçº¿ç¨åæ¶åé弿¶çå®å
¨æ§ã
ä½å³ä½¿æ¯è¿ä¸ç§å®ç°ä¸ææ ¢çä¸ç§ï¼ä¹æ¯æ ééåï¼æä»¥åéææ¥æ¶ä¸ä¸ªå¼æå¤åªæ¶åå 个ååæä½å䏿¬¡å åé ï¼åå ä¸å¼çç§»å¨æä½æ¬èº«ãåªæå½éå空äºï¼æ¥æ¶çº¿ç¨éè¦è¿å ¥ç¡ç ç¶ææ¶ï¼æéè¦è¿è¡ç³»ç»è°ç¨ãå½ç¶ï¼å¨è¿ç§æ åµä¸ï¼ä½ çééæµéæ è®ºå¦ä½é½æ²¡æè¾¾å°æå¤§å¼ã
尽管è¿è¡äºè¿äºä¼åï¼ä½å¨ééæ§è½æ¹é¢ï¼åºç¨ç¨åºå¾å®¹æç¯ä¸ä¸ªé误ï¼åéå¼çéåº¦æ¯æ¥æ¶åå¤çå¼çé度快ãè¿ä¼å¯¼è´ééä¸ç§¯åçå¼è¶æ¥è¶å¤ãä¾å¦ï¼å¨æä»¬çç¨åºä¸ï¼æä»¬åç°æä»¶è¯»å线ç¨ï¼é¶æ®µ1ï¼å è½½æä»¶çéåº¦æ¯æä»¶ç´¢å¼çº¿ç¨ï¼é¶æ®µ2ï¼å¯¹æä»¶è¿è¡ç´¢å¼çé度快å¾å¤ãç»ææ¯ï¼æ°ç¾å åèçåå§æ°æ®ä¼ä¸æ¬¡æ§ä»ç£ç读åå¹¶å¡è¿éåä¸ã
è¿ç§ä¸å½è¡ä¸ºä¼æ¶èå åå¹¶å½±åå±é¨æ§ãæ´ç³ç³çæ¯ï¼åé线ç¨ä¼æç»è¿è¡ï¼å¨æ¥æ¶ç«¯æéè¦èµæºçæ¶åï¼å´æ¶èCPUåå ¶ä»ç³»ç»èµæºæ¥åéæ´å¤çå¼ã
å¨è¿æ¹é¢ï¼Ruståé´äºUnix管éçåæ³ãUnix使ç¨ä¸ç§å·§å¦çæå·§æ¥æä¾æç§èåï¼backpressureï¼ï¼è¿«ä½¿å¿«éçåéè æ ¢ä¸æ¥ï¼Unixç³»ç»ä¸çæ¯ä¸ªç®¡é齿ä¸ä¸ªåºå®ç大å°ï¼å¦æä¸ä¸ªè¿ç¨è¯å¾åå ¥ä¸ä¸ªå·²æ»¡ç管éï¼ç³»ç»ä¼é»å¡è¯¥è¿ç¨ï¼ç´å°ç®¡éæç©ºé´ä¸ºæ¢ãRustä¸ä¸ä¹å¯¹åºçæ¯åæ¥ééï¼
use std::sync::mpsc;
let (sender, receiver) = mpsc::sync_channel(1000);
2
3
忥éé䏿®éééå®å
¨ä¸æ ·ï¼åªæ¯å¨å建æ¶ï¼ä½ éè¦æå®å®è½å®¹çº³å¤å°ä¸ªå¼ã对äºåæ¥ééï¼sender.send(value)å¯è½æ¯ä¸ä¸ªé»å¡æä½ãæ¯ç«ï¼é»å¡å¹¶ä¸æ»æ¯åäºã卿们ç示ä¾ç¨åºä¸ï¼å°start_file_reader_threadä¸çééæ¹ä¸ºè½å®¹çº³32个å¼ç忥ééåï¼å¨æä»¬çåºåæ°æ®éä¸ï¼å
å使ç¨éåå°äºä¸åä¹äºï¼èååé并没æä¸éã
# 线ç¨å®å ¨æ§ï¼Send å Sync
å°ç®å为æ¢ï¼æä»¬çæä½å°±å¥½åææçå¼é½å¯ä»¥å¨ä¸å线ç¨ä¹é´èªç±ç§»å¨åå
±äº«ãå¨å¾å¤§ç¨åº¦ä¸ç¡®å®å¦æ¤ï¼ä½Rust宿´ç线ç¨å®å
¨æºå¶ä¾èµäºä¸¤ä¸ªå
ç½®ç¹æ§ï¼std::marker::Sendåstd::marker::Syncã
- å®ç°äº
Sendçç±»åå¯ä»¥å®å ¨å°æå¼ä¼ éç»å¦ä¸ä¸ªçº¿ç¨ï¼å®ä»¬å¯ä»¥å¨ä¸å线ç¨ä¹é´ç§»å¨ã - å®ç°äº
Syncçç±»åå¯ä»¥å®å ¨å°éè¿ä¸å¯åå¼ç¨ä¼ éç»å¦ä¸ä¸ªçº¿ç¨ï¼å®ä»¬å¯ä»¥å¨ä¸å线ç¨ä¹é´å ±äº«ã
è¿éæè¯´ç âå®å ¨âï¼åæä»¬ä¸ç´ä»¥æ¥çææä¸æ ·ï¼æ²¡ææ°æ®ç«äºåå ¶ä»æªå®ä¹è¡ä¸ºã
ä¾å¦ï¼å¨process_files_in_parallel示ä¾ä¸ï¼æä»¬ä½¿ç¨éå
å°Vec<String>ä»ç¶çº¿ç¨ä¼ éå°æ¯ä¸ªå线ç¨ã彿¶æä»¬æ²¡ææåºè¿ä¸ç¹ï¼ä½è¿æå³çåéåå
¶å
å«çå符串æ¯å¨ç¶çº¿ç¨ä¸åé
çï¼å´å¨å线ç¨ä¸éæ¾ãVec<String>å®ç°äºSendï¼è¿æ¯ä¸ä¸ªAPIä¿è¯ï¼è¡¨æè¿ç§æä½æ¯æ²¡é®é¢çï¼VecåStringå
é¨ä½¿ç¨çåé
卿¯çº¿ç¨å®å
¨çã
ï¼å¦æä½ è¦ç¼åèªå·±çVecåStringç±»åï¼ä½¿ç¨å¿«éä½é线ç¨å®å
¨çåé
å¨ï¼é£ä¹ä½ å¿
须使ç¨è¯¸å¦ä¸å®å
¨æéè¿æ ·çéSendç±»åæ¥å®ç°å®ä»¬ãRust伿¨æåºä½ çNonThreadSafeVecåNonThreadSafeStringç±»å䏿¯Sendï¼å¹¶å°å®ä»¬éå¶å¨å线ç¨ç¯å¢ä¸ä½¿ç¨ãä½è¿ç§æ
åµå¾å°è§ãï¼
å¦å¾19 - 9æç¤ºï¼å¤§å¤æ°ç±»åæ¢æ¯Send忝Syncãä½ çè³æ é使ç¨#[derive]为ç¨åºä¸çç»æä½åæä¸¾è·å¾è¿äºç¹æ§ï¼Rustä¼èªå¨ä¸ºä½ å¤çãå¦æç»æä½ææä¸¾çåæ®µæ¯Sendï¼é£ä¹è¯¥ç»æä½ææä¸¾å°±æ¯Sendï¼å¦æå段æ¯Syncï¼é£ä¹å®å°±æ¯Syncã
æäºç±»åæ¯Sendä½ä¸æ¯Syncãè¿éå¸¸æ¯ææä¸ºä¹ï¼æ¯å¦mpsc::Receiverï¼å®ä¿è¯äºmpscééçæ¥æ¶ç«¯å䏿¶é´åªè¢«ä¸ä¸ªçº¿ç¨ä½¿ç¨ã
å°æ°æ¢ä¸æ¯Sendä¹ä¸æ¯Syncçç±»åï¼å¤§å¤æ¯ä»¥ä¸ç§çº¿ç¨ä¸å®å
¨çæ¹å¼ä½¿ç¨äºå¯åæ§çç±»åãä¾å¦ï¼èèstd::rc::Rc<T>ï¼å³å¼ç¨è®¡æ°æºè½æéç±»åã
å¾19 - 9. SendåSyncç±»å
妿Rc<String>æ¯Syncç±»åï¼å
许线ç¨éè¿å
±äº«å¼ç¨å
±äº«å个Rcä¼åçä»ä¹å¢ï¼å¦å¾19 - 10æç¤ºï¼å¦æä¸¤ä¸ªçº¿ç¨ç¢°å·§åæ¶å°è¯å
éRcï¼å°±ä¼åºç°æ°æ®ç«äºï¼å 为两个线ç¨é½ä¼å¢å å
±äº«çå¼ç¨è®¡æ°ãå¼ç¨è®¡æ°å¯è½ä¼åå¾ä¸åç¡®ï¼å¯¼è´ä¹ååºç°éæ¾å使ç¨ï¼use - after - freeï¼æåééæ¾ï¼double freeï¼çæ
åµï¼è¿å±äºæªå®ä¹è¡ä¸ºã

å¾19 - 10. 为ä»ä¹Rc<String>æ¢ä¸æ¯Syncä¹ä¸æ¯Send
å½ç¶ï¼Rustä¼é»æ¢è¿ç§æ åµåçãä¸é¢æ¯è®¾ç½®è¿ä¸ªæ°æ®ç«äºç代ç ï¼
use std::thread;
use std::rc::Rc;
fn main() {
let rc1 = Rc::new("ouch".to_string());
let rc2 = rc1.clone();
thread::spawn(move || { // é误
rc2.clone();
});
rc1.clone();
}
2
3
4
5
6
7
8
9
10
11
Rust伿ç»ç¼è¯è¿æ®µä»£ç ï¼å¹¶ç»åºè¯¦ç»çé误信æ¯ï¼
error[E0277]: `Rc<String>` cannot be sent between threads safely
--> concurrency_send_rc.rs:10:5
|
^^^^^ `Rc<String>` cannot be sent between
10 | thread::spawn(move || { // error
threads safely
|
= help: the trait `std::marker::Send` is not implemented for
`Rc<String>`
= note: required because it appears within the type
`[closure@... ]`
= note: required by `std::thread::spawn`
2
3
4
5
6
7
8
9
10
11
12
ç°å¨ä½ å¯ä»¥çå°SendåSyncæ¯å¦ä½å¸®å©Rust强å¶å®ç°çº¿ç¨å®å
¨çãå®ä»¬ä½ä¸ºå½æ°ç±»åç¾åä¸çé宿¡ä»¶ï¼åºç°å¨è·¨çº¿ç¨è¾¹çä¼ è¾æ°æ®ç彿°ä¸ãå½ä½ å¯å¨ä¸ä¸ªçº¿ç¨æ¶ï¼ä¼ éçéå
å¿
é¡»æ¯Sendï¼è¿æå³çå®å
å«çææå¼é½å¿
é¡»æ¯Sendãåæ ·ï¼å¦æä½ æ³éè¿ééå°å¼åéå°å¦ä¸ä¸ªçº¿ç¨ï¼è¿äºå¼ä¹å¿
é¡»æ¯Sendã
# å ä¹å¯ä»¥å°ä»»ä½è¿ä»£å¨è¿æ¥å°éé
æä»¬çåæç´¢å¼æå»ºç¨åºæ¯æç §æµæ°´çº¿çæ¹å¼æå»ºçã代ç è¶³å¤æ¸ æ°ï¼ä½æä»¬éè¦æå¨è®¾ç½®ééå¹¶å¯å¨çº¿ç¨ãç¸æ¯ä¹ä¸ï¼æä»¬å¨ç¬¬15ç« æå»ºçè¿ä»£å¨æµæ°´çº¿åªç¨äºå è¡ä»£ç 就宿äºå¤§éå·¥ä½ãæä»¬è½å¦ä¸ºçº¿ç¨æµæ°´çº¿æå»ºç±»ä¼¼çä¸è¥¿å¢ï¼
å®é ä¸ï¼å¦ææä»¬è½å°è¿ä»£å¨æµæ°´çº¿åçº¿ç¨æµæ°´çº¿ç»ä¸èµ·æ¥å°±å¥½äºãè¿æ ·æä»¬çç´¢å¼æå»ºç¨åºå°±å¯ä»¥åæè¿ä»£å¨æµæ°´çº¿çå½¢å¼ãå®å¯è½ä¼åè¿æ ·å¼å§ï¼
documents.into_iter()
.map(read_whole_file)
.errors_to(error_sender) // è¿æ»¤æéè¯¯ç»æ
.off_thread() // 为ä¸è¿°æä½å¯å¨ä¸ä¸ªçº¿ç¨
.map(make_single_file_index)
.off_thread() // 为第äºé¶æ®µåå¯å¨ä¸ä¸ªçº¿ç¨
...
2
3
4
5
6
7
ç¹æ§å 许æä»¬ä¸ºæ ååºç±»åæ·»å æ¹æ³ï¼æä»¥å®é 䏿们å¯ä»¥åå°è¿ä¸ç¹ãæä»¬é¦å ç¼åä¸ä¸ªå£°ææéæ¹æ³çç¹æ§ï¼
use std::sync::mpsc;
pub trait OffThreadExt: Iterator {
/// å°è¿ä¸ªè¿ä»£å¨è½¬æ¢ä¸ºä¸ä¸ªè·¨çº¿ç¨è¿ä»£å¨ï¼`next()`è°ç¨å¨ä¸ä¸ªåç¬çå·¥ä½çº¿ç¨ä¸è¿è¡ï¼è¿æ ·è¿ä»£å¨å循ç¯ä½å°±å¯ä»¥å¹¶åè¿è¡ã
fn off_thread(self) -> mpsc::IntoIter<Self::Item>;
}
2
3
4
5
6
ç¶åæä»¬ä¸ºè¿ä»£å¨ç±»åå®ç°è¿ä¸ªç¹æ§ãmpsc::Receiverå·²ç»æ¯å¯è¿ä»£çï¼è¿å¯¹æä»¬å¾æå¸®å©ï¼
use std::thread;
impl<T> OffThreadExt for T
where
T: Iterator + Send + 'static,
T::Item: Send + 'static
{
fn off_thread(self) -> mpsc::IntoIter<Self::Item> {
// å建ä¸ä¸ªééï¼ç¨äºä»å·¥ä½çº¿ç¨ä¼ è¾é¡¹ã
let (sender, receiver) = mpsc::sync_channel(1024);
// å°è¿ä¸ªè¿ä»£å¨ç§»å¨å°ä¸ä¸ªæ°çå·¥ä½çº¿ç¨å¹¶å¨é£éè¿è¡ã
thread::spawn(move || {
for item in self {
if sender.send(item).is_err() {
break;
}
}
});
// è¿åä¸ä¸ªä»éé䏿åå¼çè¿ä»£å¨ã
receiver.into_iter()
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
è¿æ®µä»£ç ä¸çwhereå奿¯éè¿ç±»ä¼¼äº âé忍坼é宿¡ä»¶â ä¸æè¿°çè¿ç¨ç¡®å®çãä¸å¼å§ï¼æä»¬åªåäºè¿æ ·ç代ç ï¼impl<T> OffThreadExt for Tï¼ä¹å°±æ¯è¯´ï¼æä»¬å¸æè¿ä¸ªå®ç°éç¨äºææè¿ä»£å¨ãä½Rustå¹¶ä¸è®¤å¯ãå 为æä»¬ä½¿ç¨spawnå°ç±»å为Tçè¿ä»£å¨ç§»å¨å°ä¸ä¸ªæ°çº¿ç¨ï¼æä»¥å¿
é¡»æå®T: Iterator + Send + 'staticãåå 为æä»¬è¦éè¿ééå°é¡¹åéåæ¥ï¼æä»¥å¿
é¡»æå®T::Item: Send + 'staticãæäºè¿äºä¿®æ¹ï¼Rust就满æäºã
è¿å°±æ¯Rustçç¹ç¹ï¼æä»¬å¯ä»¥èªç±å°ä¸ºè¯è¨ä¸çå 乿¯ä¸ªè¿ä»£å¨æ·»å ä¸ä¸ªå¹¶ååè½å·¥å ·ï¼ä½åææ¯å¿ é¡»å ç解并记å½é£äºç¡®ä¿å ¶å®å ¨ä½¿ç¨çéå¶æ¡ä»¶ã
# æµæ°´çº¿ä¹å¤çåºç¨
卿¬èä¸ï¼æä»¬ä»¥æµæ°´çº¿ä¸ºä¾ï¼å ä¸ºæµæ°´çº¿æ¯ä½¿ç¨ééçä¸ç§ç´è§ä¸ä¸éçæ¹å¼ã大家é½è½çè§£æµæ°´çº¿ï¼å®ä»¬å ·ä½ãå®ç¨ä¸å ·æç¡®å®æ§ãä¸è¿ï¼ééçç¨é䏿¢äºæµæ°´çº¿ï¼å®è¿æ¯ä¸ç§å¿«éã便æ·çæ¹å¼ï¼è½ä¸ºåä¸è¿ç¨ä¸çå ¶ä»çº¿ç¨æä¾å¼æ¥æå¡ã
ä¾å¦ï¼åè®¾ä½ æ³å¨åç¬ç线ç¨ä¸è¿è¡æ¥å¿è®°å½ï¼å¦å¾19 - 8æç¤ºãå
¶ä»çº¿ç¨å¯ä»¥éè¿ééå°æ¥å¿æ¶æ¯åéç»æ¥å¿è®°å½çº¿ç¨ï¼ç±äºééçSenderå¯ä»¥å
éï¼è®¸å¤å®¢æ·ç«¯çº¿ç¨é½å¯ä»¥æ¥æåéè
ï¼å°æ¥å¿æ¶æ¯åéå°åä¸ä¸ªæ¥å¿è®°å½çº¿ç¨ã
å¨åç¬ç线ç¨ä¸è¿è¡åæ¥å¿è®°å½è¿æ ·çæå¡æè¯¸å¤ä¼ç¹ãæ¥å¿è®°å½çº¿ç¨å¯ä»¥å¨éè¦æ¶è½®æ¢æ¥å¿æä»¶ï¼æ éä¸å ¶ä»çº¿ç¨è¿è¡å¤æçåè°ï¼å ¶ä»çº¿ç¨ä¹ä¸ä¼è¢«é»å¡ã卿¥å¿è®°å½çº¿ç¨æ¢å¤å·¥ä½ä¹åï¼æ¶æ¯ä¼å¨éé䏿 害å°ç§¯ç´¯ä¸æ®µæ¶é´ã
ééè¿å¯ç¨äºä¸ä¸ªçº¿ç¨åå¦ä¸ä¸ªçº¿ç¨åé请æ±å¹¶éè¦è·åæç§ååºçåºæ¯ã第ä¸ä¸ªçº¿ç¨ç请æ±å¯ä»¥æ¯ä¸ä¸ªç»æä½æå
ç»ï¼å
¶ä¸å
å«ä¸ä¸ªSenderï¼å°±åæ¯ä¸ä¸ªåæèªå·±å°åçä¿¡å°ï¼ç¬¬äºä¸ªçº¿ç¨ç¨å®æ¥åéåå¤ãè¿å¹¶ä¸æå³çè¿ç§äº¤äºå¿
é¡»æ¯åæ¥çã第ä¸ä¸ªçº¿ç¨å¯ä»¥å³å®æ¯é»å¡çå¾
ååºï¼è¿æ¯ä½¿ç¨.try_recv()æ¹æ³è½®è¯¢ååºã
å°ç®å为æ¢ï¼æä»¬ä»ç»çå·¥å · ââ ç¨äºé«åº¦å¹¶è¡è®¡ç®çåæ²»å¹¶è¡ï¼ä»¥åç¨äºæ¾æ£è¿æ¥ç»ä»¶çééï¼è¶³ä»¥æ»¡è¶³å¹¿æ³çåºç¨åºæ¯ã使们çä»ç»è¿æªç»æã
# å ±äº«å¯åç¶æ
å¨ä½ åå¸äºç¬¬8ç« ä¸çfern_simåºåçå 个æéï¼ä½ çè¨ç±»æ¤ç©æ¨¡æè½¯ä»¶å¤§å欢è¿ãç°å¨ï¼ä½ æ£å¨å¼å䏿¬¾å¤äººå®æ¶æç¥æ¸¸æï¼å
«åç©å®¶å¨æ¨¡æçä¾ç½çºªæ¯è§ä¸ç«ç¸å¹è²é«åº¦é¼ççå²åè¨ç±»æ¤ç©ãè¿ä¸ªæ¸¸æçæå¡å¨æ¯ä¸ä¸ªå¤§è§æ¨¡å¹¶è¡åºç¨ç¨åºï¼è®¸å¤çº¿ç¨ä¼ä¸ææ¶å°è¯·æ±ãé£ä¹ï¼è¿äºçº¿ç¨å¦ä½åè°ï¼ä»¥ä¾¿å¨æå
«åç©å®¶åå¤å¥½æ¶ç«å³å¼å§æ¸¸æå¢ï¼
è¿éè¦è§£å³çé®é¢æ¯ï¼è®¸å¤çº¿ç¨éè¦è®¿é®ä¸ä¸ªå ±äº«ççå¾ å å ¥æ¸¸æçç©å®¶å表ãè¿äºæ°æ®å¿ ç¶æ¯å¯åçï¼å¹¶ä¸éè¦å¨ææçº¿ç¨ä¹é´å ±äº«ã妿Rust䏿¯æå ±äº«å¯åç¶æï¼é£æä»¬è¯¥æä¹åå¢ï¼
ä½ å¯ä»¥éè¿å建ä¸ä¸ªæ°çº¿ç¨æ¥è§£å³è¿ä¸ªé®é¢ï¼è¿ä¸ªçº¿ç¨çå¯ä¸ä»»å¡å°±æ¯ç®¡çè¿ä¸ªå表ãå ¶ä»çº¿ç¨éè¿ééä¸å®è¿è¡éä¿¡ãå½ç¶ï¼è¿ä¼å ç¨ä¸ä¸ªçº¿ç¨ï¼ä¼å¸¦æ¥ä¸äºæä½ç³»ç»å¼éã
å¦ä¸ç§éæ©æ¯ä½¿ç¨Rustæä¾çç¨äºå®å ¨å ±äº«å¯åæ°æ®çå·¥å ·ãè¿äºå·¥å ·ç¡®å®åå¨ï¼å®ä»¬æ¯åºå±åè¯ï¼ä»»ä½ä½¿ç¨è¿çº¿ç¨çç³»ç»ç¨åºåé½å¾çæã卿¬èä¸ï¼æä»¬å°ä»ç»äºæ¥éï¼mutexï¼ã读åéãæ¡ä»¶åéåååæ´æ°ãæåï¼æä»¬å°å±ç¤ºå¦ä½å¨Rustä¸å®ç°å ¨å±å¯ååéã
# ä»ä¹æ¯äºæ¥éï¼
äºæ¥éï¼æéï¼ç¨äºå¼ºå¶å¤ä¸ªçº¿ç¨å¨è®¿é®ç¹å®æ°æ®æ¶ä¾æ¬¡è¿è¡ãæä»¬å°å¨ä¸ä¸èä»ç»Rustä¸çäºæ¥éãé¦å ï¼å顾ä¸ä¸å ¶ä»è¯è¨ä¸çäºæ¥éæ¯å¾ææä¹çãå¨C++ä¸ï¼äºæ¥éçä¸ä¸ªç®åç¨æ³å¯è½å¦ä¸ï¼
// C++代ç ï¼å¹¶éRust代ç
void FernEmpireApp::JoinWaitingList(PlayerId player) {
mutex.Acquire();
waitingList.push_back(player);
// 妿çå¾
çç©å®¶æ°éè¶³å¤ï¼å°±å¼å§ä¸åºæ¸¸æ
if (waitingList.size() >= GAME_SIZE) {
vector<PlayerId> players;
waitingList.swap(players);
StartGame(players);
}
mutex.Release();
}
2
3
4
5
6
7
8
9
10
11
12
å¨è¿æ®µä»£ç ä¸ï¼mutex.Acquire()åmutex.Release()è°ç¨æ è®°äºä¸´çåºçå¼å§åç»æã对äºç¨åºä¸çæ¯ä¸ªäºæ¥éï¼å䏿¶é´åªæä¸ä¸ªçº¿ç¨å¯ä»¥å¨ä¸´çåºå
è¿è¡ã妿ä¸ä¸ªçº¿ç¨å¤äºä¸´çåºï¼ææå
¶ä»è°ç¨mutex.Acquire()ç线ç¨å°è¢«é»å¡ï¼ç´å°ç¬¬ä¸ä¸ªçº¿ç¨æ§è¡å°mutex.Release()ã
æä»¬è¯´äºæ¥éä¿æ¤æ°æ®ï¼å¨è¿ä¸ªä¾åä¸ï¼äºæ¥éä¿æ¤waitingListãä¸è¿ï¼ç¡®ä¿æ¯ä¸ªçº¿ç¨å¨è®¿é®æ°æ®ä¹åé½è·åäºæ¥éï¼å¹¶å¨ä¹åéæ¾å®ï¼æ¯ç¨åºåç责任ã
äºæ¥é徿ç¨ï¼åå å¦ä¸ï¼
- å®ä»¬å¯ä»¥é²æ¢æ°æ®ç«äºï¼å³å¤ä¸ªçº¿ç¨åæ¶è¯»åç¸åå åçæ åµãå¨C++åGoä¸ï¼æ°æ®ç«äºå±äºæªå®ä¹è¡ä¸ºãåJavaåC#è¿æ ·çæç®¡è¯è¨æ¿è¯ºä¸ä¼å´©æºï¼ä½æ°æ®ç«äºçç»æä»ç¶ï¼æ¦æ¬æ¥è¯´ï¼æ¯«æ æä¹ã
- å³ä½¿ä¸å卿°æ®ç«äºï¼å³ä½¿ææç读åæä½é½æç¨åºé¡ºåºä¾æ¬¡è¿è¡ï¼å¦ææ²¡æäºæ¥éï¼ä¸å线ç¨çæä½ä¹å¯è½ä»¥ä»»ææ¹å¼äº¤éãæ³è±¡ä¸ä¸ï¼ç¼å䏿®µä»£ç ï¼å³ä½¿å¨å ¶ä»çº¿ç¨ä¿®æ¹å ¶æ°æ®æ¶ä»è½æ£å¸¸å·¥ä½ï¼åæ³è±¡ä¸ä¸è°è¯è¿æ ·ç代ç ãè¿å°±å¥½åä½ çç¨åºè¢« âå¹½çµâ å°æ°äºä¸æ ·ã
- äºæ¥éæ¯æåºäºä¸åéçç¼ç¨ï¼ä¸åéæ¯å ³äºåä¿æ¤æ°æ®çè§åï¼å¨ä½ è®¾ç½®æ°æ®æ¶è¿äºè§åå°±æç«ï¼å¹¶ä¸æ¯ä¸ªä¸´çåºé½è¦ç»´æ¤è¿äºè§åã
å½ç¶ï¼è¿äºåå æ¬è´¨ä¸æ¯ä¸æ ·çï¼ä¸åæ§å¶çç«ææ¡ä»¶ä¼è®©ç¼ç¨åå¾é¾ä»¥å¤çãäºæ¥éä¸ºæ··ä¹±çæ åµå¸¦æ¥äºä¸å®çç§©åºï¼å°½ç®¡ä¸å¦ééæå治并è¡å¸¦æ¥çç§©åºå¤ï¼ã
ç¶èï¼å¨å¤§å¤æ°è¯è¨ä¸ï¼äºæ¥éå¾å®¹æç¨éãå¨C++以å大夿°è¯è¨ä¸ï¼æ°æ®å鿝åå¼ç对象ãçæ³æ åµä¸ï¼æ³¨éä¼è¯´ææ¯ä¸ªçº¿ç¨å¨è®¿é®æ°æ®ä¹åå¿ é¡»è·åäºæ¥éï¼
class FernEmpireApp {
...
private:
// çå¾
å å
¥æ¸¸æçç©å®¶å表ãç±`mutex`ä¿æ¤ã
vector<PlayerId> waitingList;
// å¨è¯»åæåå
¥`waitingList`ä¹åå¿
é¡»è·åçéã
Mutex mutex;
...
};
2
3
4
5
6
7
8
9
ä½å³ä½¿æè¿æ ·è¯¦ç»ç注éï¼ç¼è¯å¨ä¹æ æ³å¼ºå¶è¿è¡å®å ¨è®¿é®ãå½ä¸æ®µä»£ç 忽ç¥è·åäºæ¥éæ¶ï¼å°±ä¼åºç°æªå®ä¹è¡ä¸ºãå¨å®é æ åµä¸ï¼è¿æå³çä¼åºç°æé¾éç°åä¿®å¤çé误ã
å³ä½¿å¨Javaä¸ï¼å¯¹è±¡åäºæ¥éä¹é´åå¨æç§æ¦å¿µä¸çå ³èï¼ä½è¿ç§å ³èå¹¶ä¸ç´§å¯ãç¼è¯å¨ä¸ä¼å°è¯å¼ºå¶æ§è¡ï¼å®é ä¸ï¼ç±éä¿æ¤çæ°æ®å¾å°æ°å¥½æ¯ç¸å ³å¯¹è±¡çåæ®µï¼å®é常å å«å¤ä¸ªå¯¹è±¡ä¸çæ°æ®ãé宿¹æ¡ä»ç¶å¾å¤æï¼æ³¨éä»ç¶æ¯å¼ºå¶æ§è¡çä¸»è¦ææ®µã
# Mutex<T>
ç°å¨æä»¬å°å±ç¤ºå¨Rustä¸çå¾ å表çå®ç°ã卿们çãè¨ç±»å¸å½ã游ææå¡å¨ä¸ï¼æ¯ä¸ªç©å®¶é½æä¸ä¸ªå¯ä¸çIDï¼
type PlayerId = u32;
çå¾ åè¡¨åªæ¯ä¸ä¸ªç©å®¶éåï¼
const GAME_SIZE: usize = 8;
/// çå¾
å表ä¸çç©å®¶æ°éæ°¸è¿ä¸ä¼è¶
è¿GAME_SIZEã
type WaitingList = Vec<PlayerId>;
2
3
çå¾
å表ä½ä¸ºFernEmpireAppçä¸ä¸ªå段åå¨ï¼FernEmpireAppæ¯ä¸ä¸ªåä¾ï¼å¨æå¡å¨å¯å¨æ¶è¢«è®¾ç½®å¨ä¸ä¸ªArcä¸ãæ¯ä¸ªçº¿ç¨é½æä¸ä¸ªæåå®çArcãå®å
å«äºæä»¬ç¨åºæéçææå
±äº«é
ç½®åå
¶ä»æé¡¹ãå
¶ä¸å¤§é¨åæ¯åªè¯»çãç±äºçå¾
åè¡¨æ¢æ¯å
±äº«ç忝å¯åçï¼æä»¥å¿
é¡»ç¨Mutexæ¥ä¿æ¤ï¼
use std::sync::Mutex;
/// ææçº¿ç¨é½å¯ä»¥å
±äº«è®¿é®è¿ä¸ªå¤§çä¸ä¸æç»æä½ã
struct FernEmpireApp {
...
waiting_list: Mutex<WaitingList>,
...
}
2
3
4
5
6
7
8
ä¸C++ä¸åï¼å¨Rustä¸ï¼åä¿æ¤çæ°æ®åå¨å¨Mutexå
é¨ã设置Mutexç代ç å¦ä¸ï¼
use std::sync::Arc;
let app = Arc::new(FernEmpireApp {
...
waiting_list: Mutex::new(vec![]),
});
...
2
3
4
5
6
7
å建ä¸ä¸ªæ°çMutexçèµ·æ¥å°±åå建ä¸ä¸ªæ°çBoxæArcï¼ä½BoxåArc表示å åé
ï¼èMutexä»
ç¨äºéå®ãå¦æä½ å¸æMutexå¨å ä¸åé
ï¼å°±å¿
é¡»æç¡®æå®ï¼å°±åæä»¬å¨è¿éæåçï¼å¯¹æ´ä¸ªapp使ç¨Arc::newï¼å¯¹åä¿æ¤çæ°æ®ä½¿ç¨Mutex::newãè¿äºç±»åé常ä¸èµ·ä½¿ç¨ï¼Arc便äºå¨ä¸å线ç¨ä¹é´å
±äº«æ°æ®ï¼Mutexå便äºå¤çå¨ä¸å线ç¨ä¹é´å
±äº«çå¯åæ°æ® ã
ç°å¨æä»¬å¯ä»¥å®ç°ä½¿ç¨äºæ¥éçjoin_waiting_listæ¹æ³ï¼
impl FernEmpireApp {
/// å°ä¸ä¸ªç©å®¶æ·»å å°ä¸ä¸åºæ¸¸æççå¾
å表ä¸ã
/// 妿çå¾
çç©å®¶æ°éè¶³å¤ï¼åç«å³å¼å§ä¸åºæ°æ¸¸æã
fn join_waiting_list(&self, player: PlayerId) {
// éå®äºæ¥éå¹¶è·å对å
鍿°æ®çè®¿é®æã
// `guard`çä½ç¨åå°±æ¯ä¸ä¸ªä¸´çåºã
let mut guard = self.waiting_list.lock().unwrap();
// ç°å¨è¿è¡æ¸¸æé»è¾å¤çã
guard.push(player);
if guard.len() == GAME_SIZE {
let players = guard.split_off(0);
self.start_game(players);
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
è®¿é®æ°æ®çå¯ä¸æ¹æ³æ¯è°ç¨.lock()æ¹æ³ï¼
let mut guard = self.waiting_list.lock().unwrap();
self.waiting_list.lock()ä¼é»å¡ï¼ç´å°è·åå°äºæ¥éãè¿ä¸ªæ¹æ³è°ç¨è¿åçMutexGuard<WaitingList>弿¯å¯¹&mut WaitingListçä¸ä¸ªç®åå
è£
ãå¤äºäºä¹å讨论è¿çè§£å¼ç¨å¼ºå¶è½¬æ¢ï¼æä»¬å¯ä»¥ç´æ¥å¨guardä¸è°ç¨WaitingListçæ¹æ³ï¼
guard.push(player);
guardçè³å
许æä»¬åç¨å¯¹åºå±æ°æ®çç´æ¥å¼ç¨ãRustççå½å¨æç³»ç»ç¡®ä¿è¿äºå¼ç¨ä¸ä¼æ¯guardæ¬èº«ççå½å¨ææ´é¿ã䏿æéå°±æ æ³è®¿é®Mutexä¸çæ°æ®ã
å½guardè¢«ä¸¢å¼æ¶ï¼éå°±ä¼è¢«éæ¾ãé常æ
åµä¸ï¼è¿åçå¨ä»£ç åçæ«å°¾ï¼ä½ä½ ä¹å¯ä»¥æå¨ä¸¢å¼å®ï¼
if guard.len() == GAME_SIZE {
let players = guard.split_off(0);
drop(guard); // å¨å¼å§æ¸¸ææ¶ä¸è¦ä¸ç´éå®å表
self.start_game(players);
}
2
3
4
5
# mutåMutex
æä»¬çjoin_waiting_listæ¹æ³æ²¡æä»¥å¯åå¼ç¨çæ¹å¼è·åselfï¼è¿å¯è½çèµ·æ¥å¾å¥æªï¼è³å°æä»¬ä¸å¼å§æ¯è¿ä¹è§å¾çãå®çç±»åç¾åæ¯ï¼
fn join_waiting_list(&self, player: PlayerId)
åºå±çéåVec<PlayerId>ï¼å¨è°ç¨å
¶pushæ¹æ³æ¶ç¡®å®éè¦å¯åå¼ç¨ãå®çç±»åç¾åæ¯ï¼
pub fn push(&mut self, item: T)
ç¶èï¼è¿æ®µä»£ç ç¼è¯åè¿è¡é½æ²¡æé®é¢ãè¿æ¯æä¹åäºå¢ï¼
å¨Rustä¸ï¼&mutæå³çç¬å 访é®ï¼èæ®éç&æå³çå
±äº«è®¿é®ã
æä»¬ä¹ æ¯äºç±»åä»ç¶å¯¹è±¡å°å对象ãä»å®¹å¨å°å
å®¹ä¼ é&mutè®¿é®æéãéå¸¸åªæå¨ä¸å¼å§å°±æ¥æå¯¹starshipsç&mutå¼ç¨æ¶ï¼æææè½å¤è°ç¨starships[id].engineç&mut selfæ¹æ³ï¼æè
ä½ æ¥æstarshipsï¼å¨è¿ç§æ
åµä¸ï¼æåä½ æä¸ºåé·马æ¯å
ï¼ãè¿æ¯é»è®¤æ
åµï¼å ä¸ºå¦æä½ æ²¡æå¯¹ç¶å¯¹è±¡çç¬å è®¿é®æï¼Rustéå¸¸æ æ³ç¡®ä¿ä½ 对å
¶å对象æç¬å è®¿é®æã
使¯Mutexæåæ³åå°è¿ä¸ç¹ï¼éè¿éãå®é
ä¸ï¼äºæ¥éç主è¦ä½ç¨å°±æ¯å®ç°è¿ä¸ç¹ï¼å³æä¾å¯¹å
鍿°æ®çç¬å ï¼å¯åï¼è®¿é®ï¼å³ä½¿è®¸å¤çº¿ç¨å¯è½å¯¹Mutexæ¬èº«æå
±äº«ï¼ä¸å¯åï¼è®¿é®æã
Rustçç±»åç³»ç»åè¯äºæä»¬Mutexçä½ç¨ãå®å¨æå°å¼ºå¶å®ç°ç¬å 访é®ï¼èè¿é常æ¯ç±Rustç¼è¯å¨å¨ç¼è¯æ¶éæå®æçã
ï¼ä½ å¯è½è¿è®°å¾std::cell::RefCellä¹æç±»ä¼¼åè½ï¼åªæ¯å®ä¸æ¯æå¤çº¿ç¨ãMutexåRefCell齿¯å
é¨å¯åæ§çä¸åå½¢å¼ï¼æä»¬ä¹åä»ç»è¿ãï¼
# 为ä»ä¹äºæ¥é并䏿»æ¯å¥½çéæ©
å¨å¼å§ä»ç»äºæ¥éä¹åï¼æä»¬ä»ç»äºä¸äºå¹¶åç¼ç¨æ¹æ³ï¼å¦æä½ ä»C++è½¬è¿æ¥ï¼å¯è½ä¼è§å¾è¿äºæ¹æ³åºå¥å°å®¹ææ£ç¡®ä½¿ç¨ãè¿å¹¶éå·§åï¼è¿äºæ¹æ³æ¨å¨å¯¹å¹¶åç¼ç¨ä¸æä»¤äººå°æçæ¹é¢æä¾å¼ºæåçä¿éãä» ä½¿ç¨å治并è¡çç¨åºæ¯ç¡®å®æ§çï¼ä¸ä¼åçæ»éã使ç¨ééçç¨åºä¹è¡¨ç°å¾å¾å¥½ãåæä»¬çç´¢å¼æå»ºç¨åºé£æ ·ä» å°ééç¨äºæµæ°´çº¿æä½çç¨åºæ¯ç¡®å®æ§çï¼æ¶æ¯ä¼ éçæ¶é´å¯è½ä¼ææä¸åï¼ä½ä¸ä¼å½±åè¾åºãè¯¸å¦æ¤ç±»ãå¤çº¿ç¨ç¨åºæè¿äºä¿éæ¯å¾å¥½çï¼
RustçMutex设计å ä¹å¯ä»¥è¯å®ä¼è®©ä½ æ¯ä»¥å¾æ´ç³»ç»ãæ´åçå°ä½¿ç¨äºæ¥éãä½å¼å¾å䏿¥æèä¸ä¸ï¼Rustçå®å
¨ä¿éè½è§£å³ä»ä¹é®é¢ï¼ä¸è½è§£å³ä»ä¹é®é¢ã
å®å ¨çRust代ç ä¸ä¼è§¦åæ°æ®ç«äºï¼æ°æ®ç«äºæ¯ä¸ç§ç¹å®ç±»åçé误ï¼å³å¤ä¸ªçº¿ç¨åæ¶è¯»åç¸åå åï¼äº§çæ æä¹çç»æãè¿å¾æ£ï¼æ°æ®ç«äºæ»æ¯é误ï¼èä¸å¨å®é çå¤çº¿ç¨ç¨åºä¸å¹¶ä¸ç½è§ã
ç¶èï¼ä½¿ç¨äºæ¥éç线ç¨ä¼åå°ä¸äºRustæ æ³ä¸ºä½ è§£å³çå ¶ä»é®é¢çå½±åï¼
- ææçRustç¨åºä¸ä¼åºç°æ°æ®ç«äºï¼ä½ä»ç¶å¯è½åå¨å ¶ä»ç«ææ¡ä»¶ï¼å³ç¨åºçè¡ä¸ºä¾èµäºçº¿ç¨ä¹é´çæ¶é´é¡ºåºï¼å æ¤æ¯æ¬¡è¿è¡çç»æå¯è½ä¼ææä¸åãæäºç«ææ¡ä»¶æ¯è¯æ§çï¼ä½æäºä¼è¡¨ç°ä¸ºç¨åºçä¸ç¨³å®åæé¾ä¿®å¤çé误ã以æ ç»ç»çæ¹å¼ä½¿ç¨äºæ¥éä¼å¼åç«ææ¡ä»¶ãä½ éè¦ç¡®ä¿å®ä»¬æ¯è¯æ§çã
- å ±äº«å¯åç¶æä¹ä¼å½±åç¨åºè®¾è®¡ãééå¨ä»£ç ä¸å 彿½è±¡è¾¹çï¼ä¾¿äºå°ç¬ç«çç»ä»¶åç¦»åºæ¥è¿è¡æµè¯ï¼èäºæ¥éä¼é¼å±ä¸ç§ âåªæ¯æ·»å ä¸ä¸ªæ¹æ³â ç工使¹å¼ï¼è¿å¯è½ä¼å¯¼è´ä»£ç åæä¸ä¸ªç¸äºå ³èçæ´ä½ã
- æåï¼äºæ¥éå¹¶ä¸åä¹çèµ·æ¥é£ä¹ç®åï¼æ¥ä¸æ¥ç两èå°è¯´æè¿ä¸ç¹ã
ææè¿äºé®é¢é½æ¯è¿äºå·¥å
·åºæçãå°½å¯è½ä½¿ç¨æ´ç»æåçæ¹æ³ï¼å¿
è¦æ¶å使ç¨Mutexã
# æ»é
线ç¨å¦æå°è¯è·åå®å·²ç»ææçéï¼å°±å¯è½ä¼å¯¼è´èªèº«æ»éï¼
let mut guard1 = self.waiting_list.lock().unwrap();
let mut guard2 = self.waiting_list.lock().unwrap(); // æ»é
2
å设对self.waiting_list.lock()çç¬¬ä¸æ¬¡è°ç¨æåè·åäºéãç¬¬äºæ¬¡è°ç¨åç°é已被ææï¼å æ¤å®ä¼é»å¡ï¼çå¾
éè¢«éæ¾ãä½å®ä¼æ°¸è¿çå¾
ä¸å»ï¼å 为çå¾
ççº¿ç¨æ£æ¯ææéçé£ä¸ªçº¿ç¨ã
æ¢å¥è¯è¯´ï¼Mutexä¸çé䏿¯éå½éã
è¿éçéè¯¯å¾ææ¾ãå¨å®é
ç¨åºä¸ï¼è¿ä¸¤ä¸ªlock()è°ç¨å¯è½å¨ä¸¤ä¸ªä¸åçæ¹æ³ä¸ï¼å
¶ä¸ä¸ä¸ªæ¹æ³è°ç¨äºå¦ä¸ä¸ªãåç¬çæ¯ä¸ªæ¹æ³ç代ç ï¼å¯è½çèµ·æ¥é½æ²¡é®é¢ãè¿æå
¶ä»å¯¼è´æ»éçæ
åµï¼æ¶åå¤ä¸ªçº¿ç¨åæ¶è·åå¤ä¸ªäºæ¥éãRustçåç¨ç³»ç»æ æ³ä¿æ¤ä½ é¿å
æ»éãæå¥½çé¢é²æ¹æ³æ¯å°ä¸´çåºä¿æå¾å°½å¯è½å°ï¼è¿å
¥ä¸´çåºï¼å®æå·¥ä½ï¼ç¶å离å¼ã
使ç¨ééä¹å¯è½ä¼åºç°æ»éãä¾å¦ï¼ä¸¤ä¸ªçº¿ç¨å¯è½ä¼é»å¡ï¼æ¯ä¸ªçº¿ç¨é½å¨çå¾ ä»å¦ä¸ä¸ªçº¿ç¨æ¥æ¶æ¶æ¯ãç¶èï¼åæ ·å°ï¼è¯å¥½çç¨åºè®¾è®¡å¯ä»¥è®©ä½ æè¶³å¤çä¿¡å¿ï¼å¨å®é ä¸è¿ç§æ åµä¸ä¼åçãå¨åæä»¬çåæç´¢å¼æå»ºç¨åºè¿æ ·çæµæ°´çº¿ä¸ï¼æ°æ®æµæ¯æ ç¯çãå¨è¿æ ·çç¨åºä¸ï¼æ»éå°±åå¨Unix shellæµæ°´çº¿ä¸ä¸æ ·ä¸å¤ªå¯è½åçã
# 䏿¯çäºæ¥é
Mutex::lock()åJoinHandle::join()è¿åResultçåå æ¯ä¸æ ·çï¼å¦æå¦ä¸ä¸ªçº¿ç¨åçäºææ
ï¼panicï¼ï¼è½å¤ä¼é
å°å¤ç失败æ
åµã彿们åhandle.join().unwrap()æ¶ï¼æä»¬æ¯å¨åè¯Rustå°ææ
ä»ä¸ä¸ªçº¿ç¨ä¼ æå°å¦ä¸ä¸ªçº¿ç¨ãmutex.lock().unwrap()è¿ä¸ªä¹ æ¯ç¨æ³ä¹æ¯ç±»ä¼¼çã
妿ä¸ä¸ªçº¿ç¨å¨ææMutexæ¶åçææ
ï¼Rustä¼å°è¯¥Mutexæ è®°ä¸ºä¸æ¯ç¶æãåç»ä»»ä½å°è¯éå®è¿ä¸ªä¸æ¯çMutexçæä½é½ä¼å¾å°ä¸ä¸ªéè¯¯ç»æãæä»¬ç.unwrap()è°ç¨åè¯Rustï¼å¦æåçè¿ç§æ
åµå°±è§¦åææ
ï¼å°å¦ä¸ä¸ªçº¿ç¨çææ
ä¼ æå°è¿ä¸ªçº¿ç¨ã
ä¸ä¸ªä¸æ¯çäºæ¥éæå¤ä¸¥éå¢ï¼â䏿¯â å¬èµ·æ¥å¾ä¸¥éï¼ä½è¿ç§æ åµä¸ä¸å®æ¯è´å½çãæ£å¦æä»¬å¨ç¬¬7ç« æè¯´ï¼ææ æ¯å®å ¨çãä¸ä¸ªåçææ ç线ç¨ä¼è®©ç¨åºçå ¶ä»é¨åå¤äºå®å ¨ç¶æã
é£ä¹ï¼äºæ¥éå¨åçææ
æ¶è¢«æ è®°ä¸ºä¸æ¯ï¼å¹¶ä¸æ¯å 为æ
å¿æªå®ä¹è¡ä¸ºãæ´ç¡®åå°è¯´ï¼æ¯å 为æä»¬å¯è½ä¸ç´å¨åºäºä¸åéè¿è¡ç¼ç¨ãç±äºç¨åºåçææ
并卿ªå®æä¸´çåºæä½çæ
åµä¸éåºï¼å¯è½æ´æ°äºåä¿æ¤æ°æ®çæäºåæ®µä½æ²¡ææ´æ°å
¶ä»åæ®µï¼æä»¥ä¸åéç°å¨å¯è½å·²ç»è¢«ç ´åäºãRustå°äºæ¥éæ è®°ä¸ºä¸æ¯ï¼æ¯ä¸ºäºé²æ¢å
¶ä»çº¿ç¨å¨ä¸ç¥æ
çæ
åµä¸é·å
¥è¿ç§è¢«ç ´åçç¶æï¼ä»è使æ
åµå徿´ç³ãä½ ä»ç¶å¯ä»¥éå®ä¸ä¸ªä¸æ¯çäºæ¥é并访é®å
¶ä¸çæ°æ®ï¼å¹¶ä¸å®å
¨å¼ºå¶å®æ½äºæ¥è®¿é®ï¼å¯ä»¥æ¥çPoisonError::into_inner()çææ¡£äºè§£ç¸å
³å
容ãä½ä½ ä¸ä¼æå¤å°è¿ä¹åã
# 使ç¨äºæ¥éå®ç°å¤æ¶è´¹è éé
æä»¬ä¹åæå°è¿ï¼Rustçé鿝å¤ç产è
ãåæ¶è´¹è
çãæè
æ´å
·ä½å°è¯´ï¼ä¸ä¸ªééåªæä¸ä¸ªReceiverãæä»¬ä¸è½è®©ä¸ä¸ªçº¿ç¨æ± ä¸ç许å¤çº¿ç¨å°å个mpscééç¨ä½å
±äº«çå·¥ä½å表ã
ç¶èï¼äºå®è¯æï¼ä»
ä½¿ç¨æ ååºä¸çç»ä»¶å°±æä¸ä¸ªé常ç®åçè§£å³æ¹æ³ãæä»¬å¯ä»¥å¨Receiverå¨å´æ·»å ä¸ä¸ªMutexï¼ç¶åä»ç¶å
±äº«å®ãä¸é¢æ¯ä¸ä¸ªå®ç°æ¤åè½ç模åï¼
pub mod shared_channel {
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver};
/// 对`Receiver`ç线ç¨å®å
¨å
è£
ã
#[derive(Clone)]
pub struct SharedReceiver<T>(Arc<Mutex<Receiver<T>>>);
impl<T> Iterator for SharedReceiver<T> {
type Item = T;
/// ä»è¢«å
è£
çæ¥æ¶å¨è·åä¸ä¸ä¸ªé¡¹ã
fn next(&mut self) -> Option<T> {
let guard = self.0.lock().unwrap();
guard.recv().ok()
}
}
/// å建ä¸ä¸ªæ°çééï¼å
¶æ¥æ¶å¨å¯ä»¥å¨å¤ä¸ªçº¿ç¨é´å
±äº«ã
/// å®è¿åä¸ä¸ªåéè
åä¸ä¸ªæ¥æ¶å¨ï¼å°±åæ ååºä¸ç`channel()`彿°ä¸æ ·ï¼å¹¶ä¸ææ¶å¯ä»¥ç´æ¥æ¿ä»£å®ã
pub fn shared_channel<T>() -> (Sender<T>, SharedReceiver<T>) {
let (sender, receiver) = channel();
(sender, SharedReceiver(Arc::new(Mutex::new(receiver))))
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
æä»¬ä½¿ç¨äºArc<Mutex<Receiver<T>>>ãæ³åå¨è¿éå 积å¾å¾å¤ãè¿ç§æ
åµå¨Rust䏿¯å¨C++䏿´å¸¸è§ãè¿å¯è½çèµ·æ¥ä¼è®©äººå°æï¼ä½é常ï¼å°±åå¨è¿ä¸ªä¾åä¸ä¸æ ·ï¼ä»
ä»åç§°ä¸å°±è½å¸®å©è§£éåçäºä»ä¹ï¼å¦å¾19 - 11æç¤ºã

å¾19 - 11. å¦ä½è§£è¯»å¤æç±»å
# 读åéï¼RwLock<T>ï¼
ç°å¨ï¼è®©æä»¬ä»äºæ¥é转å°std::syncï¼Rustæ ååºç线ç¨åæ¥å·¥å
·å
ï¼ä¸æä¾çå
¶ä»å·¥å
·ãæä»¬å°ç®è¦ä»ç»ï¼å 为对è¿äºå·¥å
·ç宿´è®¨è®ºè¶
åºäºæ¬ä¹¦çèå´ã
æå¡å¨ç¨åºé常æé 置信æ¯ï¼è¿äºä¿¡æ¯åªå è½½ä¸æ¬¡ï¼å¹¶ä¸å¾å°æ´æ¹ã大夿°çº¿ç¨åªæ¯æ¥è¯¢é ç½®ï¼ä½ç±äºé ç½®æ¯å¯ä»¥æ´æ¹çï¼ä¾å¦ï¼å¯è½è¦æ±æå¡å¨ä»ç£çéæ°å è½½é ç½®ï¼ï¼æä»¥æ 论å¦ä½é½å¿ é¡»ç¨éæ¥ä¿æ¤å®ãå¨è¿ç§æ åµä¸ï¼äºæ¥éå¯ä»¥å·¥ä½ï¼ä½å®ä¼æä¸ºä¸å¿ è¦çç¶é¢ã妿é 置没æååï¼çº¿ç¨ä¸åºè¯¥è½®æµæ¥è¯¢é ç½®ãè¿ç§æ åµå°±éå使ç¨è¯»åéï¼RwLockï¼ã
äºæ¥éåªæä¸ä¸ªlockæ¹æ³ï¼è读åéæä¸¤ä¸ªé宿¹æ³ï¼readåwriteãRwLock::writeæ¹æ³ç±»ä¼¼äºMutex::lockï¼å®çå¾
对åä¿æ¤æ°æ®çç¬å ãå¯å访é®ãRwLock::readæ¹æ³æä¾ä¸å¯å访é®ï¼å
¶ä¼ç¹æ¯ä¸å¤ªå¯è½éè¦çå¾
ï¼å 为许å¤çº¿ç¨å¯ä»¥åæ¶å®å
¨å°è¯»åã使ç¨äºæ¥éæ¶ï¼å¨ä»»ä½ç»å®æ¶å»ï¼åä¿æ¤çæ°æ®åªæä¸ä¸ªè¯»åè
æä¸ä¸ªåå
¥è
ï¼æè
没æï¼ãè使ç¨è¯»åéæ¶ï¼å®å¯ä»¥æä¸ä¸ªåå
¥è
æå¤ä¸ªè¯»åè
ï¼è¿ä¸Rustçå¼ç¨æºå¶å¤§è´ç¸ä¼¼ã
FernEmpireAppå¯è½æä¸ä¸ªç¨äºé
ç½®çç»æä½ï¼ç±RwLockä¿æ¤ï¼
use std::sync::RwLock;
struct FernEmpireApp {
...
config: RwLock<AppConfig>,
...
}
2
3
4
5
6
7
读åé
ç½®çæ¹æ³ä¼ä½¿ç¨RwLock::read()ï¼
/// 妿åºè¯¥ä½¿ç¨å®éªæ§ççè代ç ï¼åè¿åtrueã
fn mushrooms_enabled(&self) -> bool {
let config_guard = self.config.read().unwrap();
config_guard.mushrooms_enabled
}
2
3
4
5
éæ°å è½½é
ç½®çæ¹æ³ä¼ä½¿ç¨RwLock::write()ï¼
fn reload_config(&self) -> io::Result<()> {
let new_config = AppConfig::load()?;
let mut config_guard = self.config.write().unwrap();
*config_guard = new_config;
Ok(())
}
2
3
4
5
6
å½ç¶ï¼Rusté常éåå¼ºå¶æ§è¡å
³äºRwLockæ°æ®çå®å
¨è§åãååå
¥è
æå¤è¯»åè
çæ¦å¿µæ¯Ruståç¨ç³»ç»çæ ¸å¿ã
self.config.read()è¿åä¸ä¸ªguardï¼æä¾å¯¹AppConfigçä¸å¯åï¼å
±äº«ï¼è®¿é®ï¼self.config.write()è¿åå¦ä¸ç§ç±»åçguardï¼æä¾å¯åï¼ç¬å ï¼è®¿é®ã
# æ¡ä»¶åéï¼Condvarï¼
é常ï¼ä¸ä¸ªçº¿ç¨éè¦çå¾ æä¸ªæ¡ä»¶å为çï¼
- 卿å¡å¨å ³éæé´ï¼ä¸»çº¿ç¨å¯è½éè¦çå¾ ææå ¶ä»çº¿ç¨å®æéåºã
- å½å·¥ä½çº¿ç¨æ äºå¯åæ¶ï¼å®éè¦çå¾ ç´å°ææ°æ®éè¦å¤çã
- å®ç°åå¸å¼å ±è¯åè®®ç线ç¨å¯è½éè¦çå¾ ç´å°è¾¾å°æ³å®æ°éç对çèç¹ååºååºã
ææ¶ï¼å¯¹äºæä»¬æ³è¦çå¾
çç¹å®æ¡ä»¶ï¼ææ¹ä¾¿çé»å¡APIï¼æ¯å¦å¨æå¡å¨å
³éçä¾åä¸ä½¿ç¨JoinHandle::joinãå¨å
¶ä»æ
åµä¸ï¼æ²¡æå
ç½®çé»å¡APIãç¨åºå¯ä»¥ä½¿ç¨æ¡ä»¶å鿥æå»ºèªå·±ççå¾
æºå¶ãå¨Rustä¸ï¼std::sync::Condvarç±»åå®ç°äºæ¡ä»¶åéãCondvaræ.wait()å.notify_all()æ¹æ³ï¼.wait()ä¼é»å¡ï¼ç´å°å
¶ä»æä¸ªçº¿ç¨è°ç¨.notify_all()ã
å®é
æ
嵿¯è¿ç¨å¾®å¤æä¸äºï¼å 为æ¡ä»¶åéæ»æ¯ä¸ç±æä¸ªç¹å®Mutexä¿æ¤çæäºæ°æ®çæä¸ªç忡件ç¸å
³ãå æ¤ï¼è¿ä¸ªMutexåCondvaræ¯ç¸å
³çãè¿é没æè¶³å¤çç¯å¹
è¿è¡å®æ´çè§£éï¼ä½ä¸ºäºå¸®å©ä¹å使ç¨è¿æ¡ä»¶åéçç¨åºåï¼æä»¬å°å±ç¤ºä¸¤ä¸ªå
³é®ä»£ç çæ®µã
彿æçæ¡ä»¶åä¸ºçæ¶ï¼æä»¬è°ç¨Condvar::notify_allï¼ænotify_oneï¼æ¥å¤éä»»ä½çå¾
ç线ç¨ï¼
self.has_data_condvar.notify_all();
为äºè¿å
¥ç¡ç ç¶æå¹¶çå¾
æä¸ªæ¡ä»¶å为çï¼æä»¬ä½¿ç¨Condvar::wait()ï¼
while!guard.has_data() {
guard = self.has_data_condvar.wait(guard).unwrap();
}
2
3
è¿ä¸ªwhileå¾ªç¯æ¯ä½¿ç¨æ¡ä»¶åéçæ åä¹ æ¯ç¨æ³ãç¶èï¼Condvar::waitçç¾åä¸å¤ªå¯»å¸¸ã宿弿¥åä¸ä¸ªMutexGuardå¯¹è±¡ï¼æ¶èå®ï¼å¹¶å¨æåæ¶è¿åä¸ä¸ªæ°çMutexGuardãè¿ä½ç°äºè¿æ ·ä¸ç§é»è¾ï¼waitæ¹æ³å
éæ¾äºæ¥éï¼ç¶åå¨è¿åä¹åéæ°è·åå®ãæå¼ä¼ éMutexGuard就忝å¨è¯´ï¼âææäºä½ ï¼.wait()æ¹æ³ï¼éæ¾è¿ä¸ªäºæ¥éçç¬å æéãâ
# ååç±»å
std::sync::atomic模åå
å«ç¨äºæ éå¹¶åç¼ç¨çååç±»åãè¿äºç±»ååºæ¬ä¸ä¸æ åC++ååç±»åç¸åï¼è¿å¢å äºä¸äºé¢å¤çç±»åï¼
AtomicIsizeåAtomicUsizeæ¯ä¸å线ç¨çisizeåusizeç±»åç¸å¯¹åºçå ±äº«æ´æ°ç±»åãAtomicI8ãAtomicI16ãAtomicI32ãAtomicI64以åå®ä»¬çæ 符å·åä½ï¼å¦AtomicU8ï¼æ¯ä¸å线ç¨çi8ãi16çç±»åç¸å¯¹åºçå ±äº«æ´æ°ç±»åãAtomicBoolæ¯ä¸ä¸ªå ±äº«çå¸å°å¼ãAtomicPtr<T>æ¯ä¸å®å ¨æéç±»å*mut Tçå ±äº«å¼ã
ååæ°æ®çæ£ç¡®ä½¿ç¨è¶ åºäºæ¬ä¹¦çèå´ãå¯ä»¥è¯´ï¼å¤ä¸ªçº¿ç¨å¯ä»¥åæ¶è¯»åååå ¥ä¸ä¸ªååå¼èä¸ä¼å¯¼è´æ°æ®ç«äºã
ååç±»åæ²¡æä½¿ç¨é常çç®æ¯åé»è¾è¿ç®ç¬¦ï¼èæ¯æä¾äºæ§è¡ååæä½çæ¹æ³ï¼å
æ¬å个å è½½ãåå¨ã交æ¢ä»¥åå³ä½¿å¨å
¶ä»çº¿ç¨ä¹å¯¹ç¸åå
åä½ç½®æ§è¡ååæä½æ¶ï¼ä»è½å®å
¨ä½ä¸ºä¸ä¸ªåå
æ§è¡çç®æ¯æä½ã对ä¸ä¸ªå为atomçAtomicIsizeè¿è¡é墿ä½å¦ä¸ï¼
use std::sync::atomic::{AtomicIsize, Ordering};
let atom = AtomicIsize::new(0);
atom.fetch_add(1, Ordering::SeqCst);
2
3
4
è¿äºæ¹æ³å¯è½ä¼ç¼è¯æç¹å®çæºå¨è¯è¨æä»¤ãå¨x86 - 64æ¶æä¸ï¼è¿ä¸ª.fetch_add()è°ç¨ä¼ç¼è¯ælock incqæä»¤ï¼èæ®éçn += 1å¯è½ä¼ç¼è¯æç®åçincqæä»¤æå
¶åç§åä½ãRustç¼è¯å¨è¿å¿
é¡»æ¾å¼å´ç»ååæä½çä¸äºä¼åï¼å ä¸ºä¸æ®éçå è½½æåå¨ä¸åï¼ååæä½ä¼ç«å³åå°å
¶ä»çº¿ç¨çå½±åï¼æè
ç«å³å½±åå
¶ä»çº¿ç¨ã
åæ°Ordering::SeqCstæ¯ä¸ç§å
åæåºãå
åæåºæç¹åæ°æ®åºä¸çäºå¡é离级å«ãå®ä»¬åè¯ç³»ç»ä½ å¯¹å æå
³ç³»åæ¶é´æ ç¯çæ¦å¿µçå
³æ³¨ç¨åº¦ï¼ä¸æ§è½ç¸å¯¹ãå
åæåºå¯¹ç¨åºæ£ç¡®æ§è³å
³éè¦ï¼ä½çè§£åæ¨çèµ·æ¥å¾æ£æã幸è¿çæ¯ï¼éæ©é¡ºåºä¸è´æ§ï¼æä¸¥æ ¼çå
åæåºï¼å¸¦æ¥çæ§è½æå¤±é常ç¸å½ä½ï¼è¿ä¸å°SQLæ°æ®åºè®¾ç½®ä¸ºSERIALIZABLEæ¨¡å¼æ¶çæ§è½æå¤±ä¸åãæä»¥å¦æä¸ç¡®å®ï¼å°±ä½¿ç¨Ordering::SeqCstãRust仿 åC++ååç±»åç»§æ¿äºå
¶ä»å ç§å
åæåºæ¹å¼ï¼å¯¹åå¨çæ¬è´¨åå æå
³ç³»æåç§è¾å¼±çä¿è¯ãæä»¬è¿éä¸è®¨è®ºå®ä»¬ã
ååç±»åçä¸ä¸ªç®åç¨éæ¯ç¨äºåæ¶æä½ãå设æä»¬æä¸ä¸ªçº¿ç¨æ£å¨è¿è¡ä¸äºé¿æ¶é´è¿è¡ç计ç®ï¼æ¯å¦æ¸²æè§é¢ï¼å¹¶ä¸æä»¬å¸æè½å¤å¼æ¥åæ¶å®ãé®é¢å¨äºå¦ä½éç¥è¿ä¸ªçº¿ç¨æä»¬å¸æå®å
³éãæä»¬å¯ä»¥éè¿ä¸ä¸ªå
±äº«çAtomicBoolæ¥å®ç°ï¼
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
let cancel_flag = Arc::new(AtomicBool::new(false));
let worker_cancel_flag = cancel_flag.clone();
2
3
4
5
è¿æ®µä»£ç å建äºä¸¤ä¸ªæååä¸ä¸ªå¨å ä¸åé
çAtomicBoolçArc<AtomicBool>æºè½æéï¼å
¶åå§å¼ä¸ºfalseã第ä¸ä¸ªå为cancel_flagï¼å°çå¨ä¸»çº¿ç¨ä¸ã第äºä¸ªworker_cancel_flagå°è¢«ç§»å¨å°å·¥ä½çº¿ç¨ä¸ã
ä¸é¢æ¯å·¥ä½çº¿ç¨ç代ç ï¼
use std::thread;
use std::sync::atomic::Ordering;
let worker_handle = thread::spawn(move || {
for pixel in animation.pixels_mut() {
render(pixel); // å
线追踪 - è¿éè¦å å¾®ç§
if worker_cancel_flag.load(Ordering::SeqCst) {
return None;
}
}
Some(animation)
});
2
3
4
5
6
7
8
9
10
11
12
卿¸²ææ¯ä¸ªåç´ ä¹åï¼çº¿ç¨éè¿è°ç¨.load()æ¹æ³æ£æ¥æ å¿çå¼ï¼
worker_cancel_flag.load(Ordering::SeqCst)
妿å¨ä¸»çº¿ç¨ä¸æä»¬å³å®åæ¶å·¥ä½çº¿ç¨ï¼æä»¬å¨AtomicBoolä¸åå¨trueï¼ç¶åçå¾
线ç¨éåºï¼
// åæ¶æ¸²æã
cancel_flag.store(true, Ordering::SeqCst);
// 丢å¼ç»æï¼ç»æå¯è½æ¯`None`ã
worker_handle.join().unwrap();
2
3
4
å½ç¶ï¼è¿æå
¶ä»å®ç°æ¹å¼ãè¿éçAtomicBoolå¯ä»¥ç¨Mutex<bool>æé鿥æ¿ä»£ã主è¦çåºå«å¨äºååç±»åçå¼éæå°ãååæä½ä»ä¸ä½¿ç¨ç³»ç»è°ç¨ãå è½½æå卿ä½é常ç¼è¯æå个CPUæä»¤ã
ååç±»åæ¯ä¸ç§å
é¨å¯åæ§çå½¢å¼ï¼ç±»ä¼¼äºMutexæRwLockï¼æä»¥å®ä»¬çæ¹æ³éè¿å
±äº«ï¼ä¸å¯åï¼å¼ç¨è·åselfãè¿ä½¿å¾å®ä»¬å¯ä»¥ç¨ä½ç®åçå
¨å±åéã
# å ¨å±åé
å设æä»¬æ£å¨ç¼åç½ç»ä»£ç ãæä»¬å¸ææä¸ä¸ªå ¨å±åéï¼ä¸ä¸ªæ¯æ¬¡å¤çæ°æ®å æ¶é½ä¼éå¢ç计æ°å¨ï¼
/// æå¡å¨æåå¤ççæ°æ®å
æ°éã
static PACKETS_SERVED: usize = 0;
2
è¿æ®µä»£ç ç¼è¯æ²¡é®é¢ï¼ä½æä¸ä¸ªé®é¢ãPACKETS_SERVED æ¯ä¸å¯åçï¼æä»¥æä»¬æ°¸è¿æ æ³æ´æ¹å®ã
Rustä¼å°½å¯è½å°ä¸é¼å±ä½¿ç¨å
¨å±å¯åç¶æãç¨ const 声æç常éå½ç¶æ¯ä¸å¯åçãéæåéé»è®¤ä¹æ¯ä¸å¯åçï¼æä»¥æ æ³è·å对å
¶çå¯åå¼ç¨ãéæåéå¯ä»¥å£°æä¸º mutï¼ä½è¿æ ·è®¿é®å®æ¯ä¸å®å
¨çã
Rust对线ç¨å®å ¨æ§çåææ¯è¿äºè§åç主è¦åå ã
å ¨å±å¯åç¶æå¨è½¯ä»¶å·¥ç¨æ¹é¢ä¹æä¸è¯å½±åï¼å®å¾å¾ä¼ä½¿ç¨åºçå个é¨åè¦åæ´ç´§å¯ï¼æ´é¾æµè¯ï¼ä»¥å乿´é¾ä¿®æ¹ãä¸è¿ï¼å¨æäºæ åµä¸ç¡®å®æ²¡æåççæ¿ä»£æ¹æ¡ï¼æä»¥æä»¬æå¥½æ¾å°ä¸ç§å®å ¨çæ¹å¼æ¥å£°æå¯åéæåéã
å¨ä¿è¯çº¿ç¨å®å
¨çåæ¶æ¯æéå¢ PACKETS_SERVED çæç®åæ¹æ³æ¯å°å
¶è®¾ä¸ºååæ´æ°ï¼
use std::sync::atomic::AtomicUsize;
static PACKETS_SERVED: AtomicUsize = AtomicUsize::new(0);
2
声æè¿ä¸ªéæåéåï¼é墿°æ®å 计æ°å°±å¾ç®åäºï¼
use std::sync::atomic::Ordering;
PACKETS_SERVED.fetch_add(1, Ordering::SeqCst);
2
ååå ¨å±åéä» éäºç®åçæ´æ°åå¸å°å¼ãä¸è¿ï¼å建任ä½å ¶ä»ç±»åçå ¨å±åéç¸å½äºè¦è§£å³ä¸¤ä¸ªé®é¢ã
é¦å
ï¼åéå¿
须以æç§æ¹å¼ä¿è¯çº¿ç¨å®å
¨ï¼å¦åå®ä¸è½æ¯å
¨å±çï¼ä¸ºäºå®å
¨èµ·è§ï¼éæåéå¿
é¡»æ¢æ¯ Sync ç忝ä¸å¯åçã幸è¿çæ¯ï¼æä»¬å·²ç»çå°äºè§£å³è¿ä¸ªé®é¢çæ¹æ³ãRustæç¨äºå®å
¨å
±äº«å¯åå¼çç±»åï¼MutexãRwLock åååç±»åãå³ä½¿è¿äºç±»å被声æä¸ºä¸å¯åï¼å®ä»¬çå¼ä¹å¯ä»¥è¢«ä¿®æ¹ãè¿å°±æ¯å®ä»¬çä½ç¨ï¼è§ âmutåMutexâï¼ã
å
¶æ¬¡ï¼éæåå§åå¨åªè½è°ç¨ç¹å«æ 记为 const ç彿°ï¼ç¼è¯å¨å¯ä»¥å¨ç¼è¯æ¶è®¡ç®è¿äºå½æ°ãæ¢å¥è¯è¯´ï¼å®ä»¬çè¾åºæ¯ç¡®å®çï¼ä»
åå³äºå®ä»¬çåæ°ï¼èä¸ä¾èµäºä»»ä½å
¶ä»ç¶ææè¾å
¥è¾åºãè¿æ ·ï¼ç¼è¯å¨å¯ä»¥å°è®¡ç®ç»æä½ä¸ºç¼è¯æ¶å¸¸éåµå
¥ãè¿ä¸C++ ä¸ç constexpr 类似ã
ååç±»åï¼AtomicUsizeãAtomicBool çï¼çæé 彿°é½æ¯ const 彿°ï¼è¿ä½¿å¾æä»¬ä¹åå¯ä»¥å建ä¸ä¸ªéæç AtomicUsizeãå
¶ä»ä¸äºç±»åï¼å¦ StringãIpv4Addr å Ipv6Addrï¼ä¹æç®åç const æé 彿°ã
ä½ ä¹å¯ä»¥éè¿å¨å½æ°ç¾ååå ä¸ const æ¥å®ä¹èªå·±ç const 彿°ãRustå° const 彿°è½åçäºæ
éå¶å¨ä¸å°é¨åæä½å
ï¼è¿äºæä½æ¢å®ç¨åä¸ä¼äº§çä¸ç¡®å®çç»æãconst 彿°ä¸è½å°ç±»åä½ä¸ºæ³ååæ°ï¼åªè½ä½¿ç¨çå½å¨æï¼å¹¶ä¸å³ä½¿å¨ unsafe åä¸ï¼ä¹ä¸è½åé
å
åææä½åå§æéãä¸è¿ï¼æä»¬å¯ä»¥ä½¿ç¨ç®æ¯è¿ç®ï¼å
æ¬ç¯ç»å饱åç®æ¯è¿ç®ï¼ãä¸ä¼çè·¯çé»è¾è¿ç®ä»¥åå
¶ä» const 彿°ãä¾å¦ï¼æä»¬å¯ä»¥å建ä¸äºè¾
å©å½æ°ï¼ä½¿å®ä¹éæåéå叏鿴容æï¼å¹¶åå°ä»£ç éå¤ï¼
const fn mono_to_rgba(level: u8) -> Color {
Color {
red: level,
green: level,
blue: level,
alpha: 0xFF
}
}
const WHITE: Color = mono_to_rgba(255);
const BLACK: Color = mono_to_rgba(000);
2
3
4
5
6
7
8
9
10
11
ç»åè¿äºææ¯ï¼æä»¬å¯è½ä¼æ³è¿æ ·åï¼
static HOSTNAME: Mutex<String> =
Mutex::new(String::new()); // é误ï¼éæåéä¸çè°ç¨ä»
éäºå¸¸é彿°ãå
ç»ç»æä½åå
ç»åä½
2
ä¸å¹¸çæ¯ï¼è½ç¶ AtomicUsize::new() å String::new() æ¯ const fnï¼ä½ Mutex::new() 䏿¯ã为äºç»è¿è¿äºéå¶ï¼æä»¬éè¦ä½¿ç¨ lazy_static åºã
æä»¬å¨ âå»¶è¿æå»ºæ£å表达å¼å¼â ä¸ä»ç»è¿ lazy_static åºãä½¿ç¨ lazy_static! å®å®ä¹åéæ¶ï¼ä½ å¯ä»¥ä½¿ç¨ä»»ä½ä½ 忬¢çè¡¨è¾¾å¼æ¥åå§åå®ï¼å¨åéç¬¬ä¸æ¬¡è¢«è§£å¼ç¨æ¶è¿è¡è¯¥è¡¨è¾¾å¼ï¼å¹¶ä¸è¿ä¸ªå¼ä¼è¢«ä¿å䏿¥ä¾åç»ä½¿ç¨ã
æä»¬å¯ä»¥ä½¿ç¨ lazy_static è¿æ ·å£°æä¸ä¸ªç± Mutex æ§å¶çå
¨å± HashMapï¼
use lazy_static::lazy_static;
use std::sync::Mutex;
lazy_static! {
static ref HOSTNAME: Mutex<String> =
Mutex::new(String::new());
}
2
3
4
5
6
7
åæ ·çææ¯éç¨äºå
¶ä»å¤æçæ°æ®ç»æï¼å¦ HashMap å Dequeã对äºé£äºæ ¹æ¬ä¸å¯åä½åªæ¯éè¦å¤æåå§åçéæåéï¼å®ä¹é常æ¹ä¾¿ã
ä½¿ç¨ lazy_static! ä¼å¨æ¯æ¬¡è®¿é®éææ°æ®æ¶å¸¦æ¥å¾®å°çæ§è½å¼éãå
¶å®ç°ä½¿ç¨äº std::sync::Onceï¼è¿æ¯ä¸ä¸ªç¨äºä¸æ¬¡æ§åå§åçä½çº§åæ¥åè¯ãå¨å¹åï¼æ¯æ¬¡è®¿é®å»¶è¿éæåéæ¶ï¼ç¨åºé½ä¼æ§è¡ä¸æ¡ååå è½½æä»¤ï¼ä»¥æ£æ¥åå§åæ¯å¦å·²ç»å®æãï¼Once ç¨éæ¯è¾ç¹æ®ï¼æä»¥æä»¬è¿éä¸è¯¦ç»ä»ç»ãéå¸¸ä½¿ç¨ lazy_static! æ´æ¹ä¾¿ãä¸è¿ï¼å®å¨åå§åéRuståºæ¶å¾æç¨ï¼ä¾å¦ï¼è§ âlibgit2çå®å
¨æ¥å£âãï¼
# å¨Rustä¸ç¼åå¹¶å代ç çä½éª
æä»¬å±ç¤ºäºå¨Rustä¸ä½¿ç¨çº¿ç¨çä¸ç§ææ¯ï¼åå - åå¹¶å¹¶è¡ãéé以å使ç¨éçå ±äº«å¯åç¶æãæä»¬çç®æ æ¯å¯¹Rustæä¾çè¿äºé¨åè¿è¡å¾å¥½çä»ç»ï¼éç¹æ¯å®ä»¬å¦ä½ç»åå°å®é ç¨åºä¸ã
Ruståæå®å ¨æ§ï¼æä»¥ä»ä½ å³å®ç¼åå¤çº¿ç¨ç¨åºçé£ä¸å»èµ·ï¼éç¹å°±å¨äºæå»ºå®å ¨ãç»æåçéä¿¡ã让线ç¨å°½å¯è½ä¿æé离æ¯è®©Rustç¸ä¿¡ä½ æåçäºæ æ¯å®å ¨çå¥½æ¹æ³ãç¢°å·§çæ¯ï¼éç¦»ä¹æ¯ç¡®ä¿ä½ æåçäºæ æ£ç¡®ä¸å¯ç»´æ¤çå¥½æ¹æ³ã
忬¡å¼ºè°ï¼Rustå¼å¯¼ä½ ç¼ååºä¼ç§çç¨åºã
æ´éè¦çæ¯ï¼Rustå è®¸ä½ ç»ååç§ææ¯å¹¶è¿è¡å°è¯ãä½ å¯ä»¥å¿«éè¿ä»£ï¼ä¸ç¼è¯å¨ âäºè®ºâ æ¯è°è¯æ°æ®ç«äºè½è®©ä½ æ´å¿«å°æ£ç¡®è¿è¡ç¨åºã