日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入理解并行编程-分割和同步设计(四)

發布時間:2023/12/10 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解并行编程-分割和同步设计(四) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文鏈接??? 作者:paul??? 譯者:謝寶友,魯陽,陳渝

圖1.1:設計模式與鎖粒度

圖1.1是不同程度同步粒度的圖形表示。每一種同步粒度都用一節內容來描述。下面幾節主要關注鎖,不過其他幾種同步方式也有類似的粒度問題。

1.1. 串行程序

圖1.2:Intel處理器的MIPS/時鐘頻率變化趨勢

如果程序在單處理器上運行的足夠快,并且不與其他進程、線程或者中斷處理程序發生交互,那么您可以將代碼中所有的同步原語刪掉,遠離它們所帶來的開銷和復雜性。好多年前曾有人爭論摩爾定律最終會讓所有程序都變得如此。但是,隨著2003年以來Intel CPU的CPU MIPS和時鐘頻率增長速度的停止,見圖1.2,此后要增加性能,就必須提高程序的并行化程度。關于是否這種趨勢會導致一塊芯片上集成幾千個CPU的爭論不會很快停息,但是考慮到Paul是在一臺雙核筆記本上敲下這句話的,SMP的壽命極有可能比你我都長。另一個需要注意的地方是以太網的帶寬持續增長,如圖1.3所示。這種增長會導致多線程服務器的產生,這樣才能有效處理通信載荷。

圖1.3:以太網帶寬 v.s. Intel x86處理器的性能

請注意,這并不意味這您應該在每個程序中使用多線程方式編程。我再一次說明,如果一個程序在單處理器上運行的很好,那么您就從SMP同步原語的開銷和復雜性中解脫出來吧。圖1.4中哈希表查找代碼的簡單之美強調了這一點。


01 struct hash_table
02?
03{
04?
05 long nbuckets;
06?
07 struct node **buckets;
08?
09};
10?
11 typedef struct node {
12?
13 unsigned long key;
14?
15 struct node *next;
16?
17} node_t;
18?
19 int hash_search(struct hash_table *h, long key)
20?
21{
22?
23 struct node *cur;
24?
25cur = h->buckets[key % h->nbuckets];
26?
27 while (cur != NULL) {
28?
29 if (cur->key >= key) {
30?
31 return (cur->key == key);
32?
33}
34?
35cur = cur->next;
36?
37}
38?
39 return 0;
40?
41}

圖1.4:串行版的哈希表搜索算法

1.2. 代碼鎖

代碼鎖是最簡單的設計,只使用全局鎖。在已有的程序上使用代碼鎖,可以很容易的讓程序可以在多處理器上運行。如果程序只有一個共享資源,那么代碼鎖的性能是最優的。但是,許多較大且復雜的程序會在臨界區上執行許多次,這就讓代碼鎖的擴展性大大受限。


01spinlock_t hash_lock;
02?
03 struct hash_table
04?
05{
06?
07 long nbuckets;
08?
09 struct node **buckets;
10?
11};
12?
13 typedef struct node {
14?
15 unsigned long key;
16?
17 struct node *next;
18?
19} node_t;
20?
21 int hash_search(struct hash_table *h, long key)
22?
23{
24?
25 struct node *cur;
26?
27 int retval;
28?
29spin_lock(&hash_lock);
30?
31cur = h->buckets[key % h->nbuckets];
32?
33 while (cur != NULL) {
34?
35 if (cur->key >= key) {
36?
37retval = (cur->key == key);
38?
39spin_unlock(&hash_lock);
40?
41 return retval;
42?
43}
44?
45cur = cur->next;
46?
47}
48?
49spin_unlock(&hash_lock);
50?
51 return 0;
52?
53}

圖1.5:基于代碼鎖的哈希表搜索算法

因此,您最好在只有一小段執行時間在臨界區程序,或者對擴展性要求不高的程序上使用代碼鎖。這種情況下,代碼鎖可以讓程序相對簡單,和單線程版本類似,如圖1.5所示。但是,和圖1.4相比,hash_search()從簡單的一行return變成了3行語句,因為在返回前需要釋放鎖。

圖1.6:鎖競爭

并且,代碼鎖尤其容易引起“鎖競爭”,一種多個CPU并發訪問同一把鎖的情況。照顧一群小孩子(或者像小孩子一樣的老人)的SMP程序員肯定能馬上意識到某樣東西只有一個的危險,如圖1.6所示。

該問題的一種解決辦法是下節描述的“數據鎖”。

1.3. 數據鎖


01 struct hash_table
02{
03 long nbuckets;
04 struct bucket **buckets;
05};
06?
07 struct bucket {
08spinlock_t bucket_lock;
09node_t *list_head;
10};
11?
12 typedef struct node {
13 unsigned long key;
14 struct node *next;
15} node_t;
16?
17 int hash_search(struct hash_table *h, long key)
18{
19 struct bucket *bp;
20 struct node *cur;
21 int retval;
22?
23bp = h->buckets[key % h->nbuckets];
24spin_lock(&bp->bucket_lock);
25cur = bp->list_head;
26 while (cur != NULL) {
27 if (cur->key >= key) {
28retval = (cur->key == key);
29spin_unlock(&bp->hash_lock);
30 return retval;
31}
32cur = cur->next;
33}
34spin_unlock(&bp->hash_lock);
35 return 0;
36}

圖1.7:基于數據鎖的哈希表搜索算法

許多數據結構都可以分割,數據結構的每個部分帶有一把自己的鎖。這樣雖然每個部分一次只能執行一個臨界區,但是數據結構的各個部分形成的臨界區就可以并行執行了。在鎖競爭必須降低時,和同步開銷不是主要局限時,可以使用數據鎖。數據鎖通過將一塊過大的臨界區分散到各個小的臨界區來減少鎖競爭,比如,維護哈希表中的per-hash-bucket臨界區,如圖1.7所示。不過這種擴展性的增強帶來的是復雜性的提高,增加了額外的數據結構struct bucket。

圖1.8:數據鎖

和圖1.6中所示的緊張局面不同,數據鎖帶來了和諧,見圖1.8——在并行程序中,這總是意味著性能和可擴展性的提升。基于這種原因,Sequent在它的DYNIX和DYNIX/ptx操作系統中大量使用了數據鎖[BK85][Inm85][Gar90][Dov90][MD92][MG92][MS93]。

不過,那些照顧過小孩子的人可以證明,再細心的照料也不能保證一切風平浪靜。同樣的情況也適用于SMP程序。比如,Linux內核維護了一種文件和目錄的緩存(叫做“dcache”)。該緩存中的每個條目都有一把自己的鎖,但是對應根目錄的條目和它的直接后代相較于其他條目更容易被遍歷到。這將導致許多CPU競爭這些熱門條目的鎖,就像圖1.9中所示的情景。

圖1.9:數據鎖出現問題

在許多情況下,可以設計算法來減少數據沖突的次數,某些情況下甚至可以完全消滅沖突(像Linux內核中的dcache一樣[MSS04])。數據鎖通常用于分割像哈希表一樣的數據結構,也適用于每個條目用某個數據結構的實例表示這種情況。2.6.17內核的task list就是后者的例子,每個任務結構都有一把自己的proc_lock鎖。

在動態分配結構中,數據鎖的關鍵挑戰是如何保證在已經獲取鎖的情況下結構本身是否存在。圖1.7中的代碼通過將鎖放入靜態分配并且永不釋放的哈希桶,解決了上述挑戰。但是,這種手法不適用于哈希表大小可變的情況,所以鎖也需要動態分配。在這種情況,還需要一些手段來阻止哈希桶在鎖被獲取后這段時間內釋放。

小問題1.1:當結構的鎖被獲取時,如何防止結構被釋放呢?

1.4. 數據所有權

數據所有權方法按照線程或者CPU的個數分割數據結構,這樣每個線程/CPU都可以在不需任何同步開銷的情況下訪問屬于它的子集。但是如果線程A希望訪問另一個線程B的數據,那么線程A是無法直接做到這一點的。取而代之的是,線程A需要先與線程B通信,這樣線程B以線程A的名義執行操作,或者,另一種方法,將數據遷移到線程A上來。

數據所有權看起來很神秘,但是卻應用得十分頻繁。

1. 任何只能被一個CPU或者一個線程訪問的變量(C或者C++中的auto變量)都屬于這個CPU或者這個進程。

2. 用戶接口的實例擁有對應的用戶上下文。這在與并行數據庫引擎交互的應用程序中十分常見,這讓并行引擎看起來就像順序程序一樣。這樣的應用程序擁有用戶接口和他當前的操作。顯式的并行化只在數據庫引擎內部可見。

3. 參數模擬通常授予每個線程一段特定的參數區間,以此達到某種程度的并行化。

如果共享比較多,線程或者CPU間的通信會帶來較大的復雜性和通信開銷。不僅如此,如果使用的最多的數據正好被一個CPU擁有,那么這個CPU就成為了“熱點”,有時就會導致圖1.9中的類似情況。不過,在不需要共享的情況下,數據所有權可以達到理想性能,代碼也可以像圖1.4中所示的順序程序例子一樣簡單。最壞情況通常被稱為“尷尬的并行化”,而最好情況,則像圖1.8中所示一樣。

另一個數據所有權的重要實例發生在數據是只讀時,這種情況下,所有線程可以通過復制來“擁有”數據。

1.5鎖粒度與性能

本節以一種數學上的同步效率的視角,將視線投向鎖粒度和性能。對數學不敢興趣的讀者可以跳過本節。

本節的方法是用一種關于同步機制效率的粗略隊列模型,該機制只操作一個共享的全局變量,基于M/M/1隊列。M/M/1隊列。

(本節未翻譯)

總結

以上是生活随笔為你收集整理的深入理解并行编程-分割和同步设计(四)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 一本免费视频 | 亚洲精品国产精品乱码不99按摩 | 亚洲色图欧洲色图 | jizz性欧美23 | 色丁香六月 | 亚洲天堂成人在线观看 | 在线超碰 | 免费在线观看成人 | 在线观看入口 | 国产精品欧美日韩 | 日本免费网站在线观看 | 无人在线观看高清视频 | 国产一区不卡在线观看 | 免费三级黄 | 国产精品视频亚洲 | 国产精品久久网站 | 国产高清无遮挡 | av手机在线免费观看 | 影音先锋在线中文字幕 | 特级丰满少妇一级aaaa爱毛片 | 日本少妇bbb | 久久久久久久久久网站 | 暖暖免费观看日本版 | 91人人视频 | a视频在线观看免费 | 亚洲第一福利网站 | 美女主播在线观看 | 国产精品美女久久久免费 | 97se.com| 毛片黄片免费看 | 超碰福利在线观看 | 免费在线观看国产精品 | 久久国产精品毛片 | 日韩一区二区精品 | 亚洲制服在线观看 | 九九热这里有精品视频 | 丝袜国产一区 | 婷婷综合色 | 亚洲爱v | 99资源站 | 91青青草视频 | 国产精品视频亚洲 | 欧美亚州 | 美女视频黄色 | 欧美久久一区二区 | 亚洲性xxx| 中出白浆| 天堂av2021 | 日本免费精品视频 | 色就色欧美| 欧美性猛交乱大交 | 亚洲调教欧美在线 | 亚洲一区中文字幕永久在线 | 日本少妇久久久 | 日本精品在线一区 | 丰满少妇一区二区三区视频 | 亚洲一页 | 97天天操 | 三度诱惑免费版电影在线观看 | www成人在线观看 | 女av在线| 日韩黄色片免费看 | 国产亚洲一区在线 | 国产精品主播在线 | 欧美xxxx日本和非洲 | 亚洲av无码精品一区二区 | 美女扒开粉嫩的尿囗给男生桶 | 草视频在线 | 91精品久久久久久久 | 韩国av毛片 | 深夜激情网站 | 免费观看黄色网址 | 色欲一区二区三区精品a片 在线观看黄网站 | 成年人一级片 | 无码日韩精品视频 | 蜜臀久久99精品久久久画质超高清 | 国产精选视频在线观看 | 日本网站免费观看 | 97视频精品 | 四虎永久在线精品 | 黄色无遮挡网站 | 欧美日韩视频无码一区二区三 | 欧美日韩乱国产 | 日韩不卡一二三 | 在线播放中文字幕 | 天堂资源最新在线 | 亚洲一区二区三区免费 | 久久久www成人免费精品 | 91男女视频| 国产91在线播放 | 午夜视频1000 | 伊人久久久久噜噜噜亚洲熟女综合 | 快射视频网站 | 国模私拍一区二区三区 | 中国成人av| 亚洲欧美日本在线观看 | 国产一级淫 | 日韩美女啪啪 | 亚洲操操|