張 楊,董士程
(河北科技大學信息科學與工程學院,石家莊 050018)
(?通信作者電子郵箱zhangyang@hebust.edu.cn)
同步控制是并發程序中用于保證程序狀態和數據正確的必備措施,目前學術界和工業界提出了多種同步控制方式,包括鎖、原子塊和軟件事務型內存。鎖是目前使用較為廣泛且程序員熟悉度較高的一種同步控制方式;原子塊使用樂觀鎖策略以原子方式更新數據,操作簡單,但是原子操作的程序編寫相對復雜;軟件事務型內存使用事務機制實現并發操作,但在大量事務執行時對硬件要求較高,在數據競爭頻繁的情況下開銷較大。在多核時代,雖然使用鎖會遇到鎖競爭問題,但是鎖仍然是目前作為同步控制的主要方式。
Java 語言提供了同步鎖、可重入鎖、讀寫鎖、郵戳鎖等多種類型的鎖,其中同步鎖是一種互斥鎖,程序開發者多以同步方法或同步塊的形式使用同步鎖;可重入鎖是一種互斥鎖,它和同步鎖具有相同的基本行為和語義,但是在同步鎖的基礎上擴展了許多功能;讀寫鎖除了提供了可重入鎖的一些特性外,又把鎖分為讀鎖和寫鎖,讀寫鎖允許更大程度的并發;從JDK1.8 版本開始引入的郵戳鎖還提供了鎖升級、降級、優化讀等操作。每種機制都有優缺點與各自的適用場景,這要求程序開發者必須熟練掌握它們的特點,并在并發軟件開發時作出正確的選擇。
多種鎖機制并存的局面以及在使用不同鎖機制時程序性能的差異情況導致程序開發者在選擇鎖機制時常常感到困惑,以往的做法是程序員手動地把程序從一種同步機制改寫為另一種同步機制,但這要求程序員對每種同步機制都非常的熟悉,手動的改寫也容易給程序引入新的錯誤,破壞了程序的可維護性。一些研究使用自動重構工具幫助程序員在多種鎖機制之間進行轉換,比如針對重入鎖以及讀寫鎖提出了一種自動重構算法[1],或者面向可定制鎖[2]和郵戳鎖[3]的自動重構方法,以及在進行優化同步瓶頸的研究中提出的一種鎖分解方式[4]。雖然上述方式可以幫助程序開發人員比較各種鎖的性能,但是有時不成熟的重構工具往往會給程序引入一些錯誤,特別是對于并發程序。從目前的研究來看,大部分工作局限于對于鎖的使用及其相互轉化,對于鎖影響程序性能的原因缺乏全面的認識,缺少對鎖機制的直接推薦使用方法,而且將機器學習算法應用于鎖機制的研究還較少。
針對目前研究存在的問題,本文以并發程序中的鎖機制作為主要研究對象,研究其制約性能發揮的因素。為了解決上述鎖機制選擇困難的問題,本文提出了一種幫助并發程序開發人員選擇鎖機制的推薦方法LockRec,它基于已有的并發程序信息,使用改進的隨機森林算法構建鎖機制推薦模型,可以幫助開發人員在同步鎖、可重入鎖、讀寫鎖、郵戳鎖四種鎖之中進行選擇,使用UCI 的公開四種數據集對提出的模型進行驗證,推薦準確率平均值可達95.1%。此外,本文還對兩個真實程序給出了鎖機制的推薦結果以及使用推薦前后的鎖機制性能對比,結果顯示推薦后的程序性能平均加速比分別為1.35、1.29,證明LockRec 可以有效地幫助開發者選擇合適的鎖機制。
為了提高并發編程的效率,學術界提出了很多輔助并發編程的技術和工具,國內外許多大學和研究機構也對同步機制相關的問題進行了研究。Sch?fer等[5]對如何正確地重構并發程序進行了研究,并保證程序正確地進行同步控制,設計了一個軟件重構工具Relocker,該工具可以實現源對源的鎖重構。Rose 等[6]通過對相關程序進行檢測,收集在執行時有關鎖關系的信息,從而對多態鎖類型進行動態推理,以便檢測出在多線程Java 程序中的數據競爭。此外,Baum 等[7]對面向軟件事務性內存的重構技術進行了研究;Ernst等[8-9]提出了一種形式化語義的鎖規范,使用抽象解釋和類型理論兩種不同的分析方式來表達形式語義,可以正確推斷和檢查Java 鎖規則的工具。AutoLocker[10]是一個鎖的推測工具,可以實現對象訪問前加鎖和解鎖操作,但是沒有研究如何在不同的鎖之間進行推薦。雖然上述方式可以幫助程序開發人員比較各種鎖的性能,但是有時不成熟的重構工具往往會給程序引入一些錯誤,特別是對于并發程序。這種改寫的不足之處表現在:第一,對程序員的要求較高,即要求程序員對每種同步機制都非常地熟悉;第二,浪費了寶貴的時間,程序員需要處理那些與業務邏輯不相關的內容,不能集中精力處理核心業務邏輯;第三,手動的改寫容易給程序引入新的錯誤,破壞了程序的可維護性;第四,不同鎖機制的性能受多種因素影響,難于抉擇。此外,有些程序員通過借助已有經驗的方式來選擇鎖,但是這種選擇方式缺乏靈活性,一旦環境改變,選擇的鎖機制則不一定適用。因此,迫切需要對鎖機制的推薦方法進行研究,并提供相應的算法支持自動重構。
近年來,利用大規模代碼資源中蘊涵的眾多知識進行智能化軟件開發具有非常重要的理論與應用價值。Alon等[11]提出了一種將代碼片段表示為連續分布式向量的神經網絡模型,其主要思想是將代碼片段表示為一個固定長度的代碼向量,它可以用來預測代碼片段的語義屬性。傳統的基于信息檢索的方法往往將程序視為自然語言文本,這可能會錯過源代碼的重要語義信息,所以Zhang 等[12]提出了一種新的基于抽象語法樹的神經網絡用于源代碼表示,基于語句向量的序列,采用雙向循環神經網絡模型,利用語句的自然性,最終產生代碼片段的向量表示。Raychev 等[13]提出了一種新的方法來預測從大代碼庫中得到的程序屬性,其從“大代碼”中學習一個概率模型,并使用這個模型來預測新的、看不見的程序的屬性。Madeiral 等[14]提出了一個收集和存儲bug 到一個可擴展的bug 基準中的項目,從GitHub 上托管的開源項目中找到潛在的缺陷和修補程序版本對,用于Java中的自動修復研究。Saha 等[15]提供了一個jar,用于研究Java 程序自動調試、補丁和測試的大型數據集,其由1 158 個錯誤和補丁組成,這些錯誤和補丁來自8個大型流行的開源Java項目,涵蓋8個不同的著名應用程序類別。當前對于鎖機制使用的代碼推薦的相關研究尚有欠缺,目前大部分工作也是關注于使用相似代碼來給予推薦,對于鎖機制的使用無法在程序開發初期就能給出相應的推薦。
本章給出了同步鎖、可重入鎖、讀寫鎖、郵戳鎖的性能分析結果,這里使用ArrayList、HashMap、LinkedList、TreeSet四種線程不安全的數據結構,使用多個線程對其進行讀寫操作,利用不同的鎖機制對其讀寫操作進行保護,將其變為線程安全的操作。這里選擇使用的數據結構、執行線程數、讀寫線程比例以及執行次數等四種變量進行執行時間的分析,其中每個線程將執行500 次的讀操作或寫操作,所有實驗數據是在執行5 次的基礎上取平均值后得到的。圖1 給出了四種數據結構使用四種鎖機制(其中郵戳鎖分為優化讀鎖形式與未優化的形式)的性能測試結果,在實驗中分別選擇10和100線程來執行讀寫操作,同時選取線程總數10%的作為讀線程或寫線程的數量(R表示讀線程數,W表示寫線程數)。

圖1 不同ArrayList線程的性能對比Fig.1 Performance comparison of different ArrayList threads
如圖1(a)所示,ArrayList 使用四種鎖時,在總線程為10且讀寫線程比為1∶9 時,使用讀寫鎖的時間最小,同步鎖與可重入鎖時間一樣,兩種郵戳鎖的時間最多,其中優化讀鎖的要小于未優化讀鎖的時間;讀寫線程比為9∶1 時,執行時間均有所減少,使用讀寫鎖的時間仍是最小的,使用兩種郵戳鎖的時間仍較多。如圖1(b)所示,在總線程為100 且讀寫線程比為1∶9 時,使用可重入鎖與讀寫鎖的時間最少,同步鎖時間最多,使用兩種郵戳鎖的時間多于可重入鎖,但少于同步鎖的,其中優化讀鎖的要小于未優化讀鎖的時間;讀寫線程比為9∶1 時,執行時間均有所減少,不同鎖的執行時間相近,使用可重入鎖與讀寫鎖的時間仍要少于其他鎖。
HashMap 在總線程為10 且讀寫線程比為1∶9 時(如圖2(a)所示),不同鎖的執行時間相近;讀寫線程比為9∶1時,使用同步鎖與可重入鎖的執行時間均有所減少,其他鎖執行時間沒有明顯變化,使用同步鎖的時間最少。在總線程為100且讀寫線程比為1∶9時(如圖2(b)所示),使用同步鎖時間最多,其他鎖的時間則相近,但使用兩種郵戳鎖的時間要多于可重入鎖跟讀寫鎖,其中優化讀鎖的要大于未優化讀鎖的時間;讀寫線程比為9∶1 時,使用同步鎖的時間仍是最多的,可重入鎖與郵戳鎖的執行時間都有所減少,使用讀寫鎖的時間變化不大。

圖2 不同HashMap線程的性能比較Fig.2 Performance comparison of different HashMap threads
當考慮LinkedList數據結構在使用四種鎖時,當總線程為10 且讀寫線程比為1∶9 時(如圖3(a)所示),不同鎖的執行時間比較接近;讀寫線程比為9∶1 時,執行時間均有所增加,使用同步鎖與可重入鎖的時間是最大的,使用兩種郵戳鎖的時間是最小的,其中優化讀鎖的要小于未優化讀鎖的時間。在總線程為100 且讀寫線程比為1∶9 時(如圖3(b)所示),不同鎖的執行時間相近,使用同步鎖的要小于其他鎖的時間;讀寫線程比為9∶1 時,執行時間均有所增加,使用讀寫鎖的時間是最小的可重入鎖與兩種郵戳鎖的時間相近,都大于使用同步鎖的時間。

圖3 不同LinkedList線程的性能比較Fig.3 Performance comparison of different LinkedList threads
對于TreeSet,在總線程為10 且讀寫線程比為1∶9 時(如圖4(a)所示),使用郵戳鎖的時間最少,其中優化讀鎖的時間要小于未優化讀鎖的時間,讀寫鎖的時間最少,可重入鎖的時間較多;讀寫線程比為9∶1 時,執行時間均有所減少,使用兩種郵戳的時間仍是最小的,其他鎖的時間相近。在總線程為100且讀寫線程比為1∶9時(如圖4(b)所示),使用讀寫鎖的時間最少,使用同步鎖與可重入鎖的時間最多,使用兩種郵戳鎖的時間多于讀寫鎖,但少于另外兩種鎖;讀寫線程比為9∶1時,執行時間均有所減少,使用讀寫鎖的時間仍要少于其他鎖,使用同步鎖與可重入鎖的時間仍較多。

圖4 不同TreeSet線程的性能比較Fig.4 Performance comparison of different TreeSet threads
綜合上述分析可以得出以下結論:
1)不同線程總數和不同讀寫線程的比例對使用鎖的應用程序的性能有較大影響;
2)對于使用同一個數據結構的應用程序,使用不同鎖的程序性能往往不同;
3)即使每次運行的線程數量相同,不同數據結構的鎖應用程序性能也不同;
4)一個鎖機制并不是絕對優于另一個鎖機制,手動的選擇比較困難。
通過對性能結果的分析,發現對鎖結構進行決策是一項困難的任務,并且其影響因素有很多,單純依靠經驗判斷很難抉擇,因此迫切需要提供一種方法實現不同鎖機制的推薦,幫助程序員了解程序使用哪一種鎖性能較好。
本章首先給出面向不同鎖機制的推薦框架,然后對推薦系統的各個實現部分進行詳細描述。
在推薦框架中,首先對使用程序靜態分析工具對鎖的并發程序信息進行收集,抽取如數據結構、線程數等程序相關的特征屬性值;其次將得到的樣本數據經過抽樣[16]算法處理后,輸入到隨機森林模型中,進行模型訓練;最后分析驗證模型的適用性以及合理性,從而得到鎖機制推薦模型。當有一個待推薦的并發程序時,收集其相關特征屬性并輸入到鎖機制推薦模型中,輸出推薦使用的鎖機制。鎖機制的推薦框架如圖5所示。

圖5 推薦框架Fig.5 Recommendation framework
特征選擇是從原始特征中根據一定的評估準則剔除一些不相關特征而保留一些最有效特征的過程,且在特征選擇后分類正確率比選擇前更高或近似。在鎖機制推薦的模型中,本文首先使用CK(https://github.com/mauricioaniche/ck)工具收集58 個程序相關的特征向量,其中包括方法級的參數(如:使用的數據結構、線程數、方法權重等)以及類參數(如:同步字段數量、同步方法數量等)。在多數情況下,由于選取的初始特征向量較多,部分特征的數值是缺失的,存在數據不平衡的問題,所以會使少數類的分類器的性能下降。由于初始選取的特征向量較多,會導致多數特征值存在缺失,就會造成訓練樣本成為少數類樣本,影響模型的泛化能力,產生過擬合現象,所以這里采用合成少數過采樣技術(Synthetic Minority Oversampling Technique,SMOTE)工具,使用過采樣方法,利用少類完全樣本生成新樣本來提升少數類完全樣本數量,從而獲得有效的分類模型。鎖機制部分特征屬性說明如表1所示。

表1 特征屬性說明Tab.1 Feature attribute description
為了更直觀地觀察不同特征屬性對于鎖機制選擇的重要性區分,通過選取五個相關性最高的屬性進行熱力圖繪制,如圖6 所示。兩個屬性間的相關性使用皮爾遜相關系數進行計算,該系數反映了兩個變量線性相關程度的統計量[17]。可以看到對于鎖機制(lockid)的選擇,使用的數據結構(Structure)、線程數(NumOfThread)、操作數(NumOfOperate)、方法權重(methodWmc)等屬性與其之間的相關性數值分別是0.641、0.612、0.499、0.69,根據這些相關性將使用改進的隨機森林分類算法對數據進行分析。

圖6 特征屬性相關性熱力圖Fig.6 Heat map of feature attribute correlation
考慮到對于不同鎖機制的選擇時影響因素較多,所以需要選取一個合適的推薦模型進行推薦。隨機森林算法能夠處理很高維度的數據,并且在訓練數據較多的情況時,訓練速度較快。盡管隨機森林具有很多優點,但仍然有不足之處,傳統隨機森林模型中的決策樹擁有相同的投票權重,而且隨著隨機森林構建的擴大,決策樹生成過于龐大的子葉,使得實驗預測結果過擬合,這影響了其整體分類能力的可靠性,由于每棵決策樹在投票時權重都相等,并且存在生成過于龐大的子葉現象,會影響隨機森林的整體分類能力[18]。
為了解決上述問題,采用基于錯誤的剪枝法和Kappa 系數加權隨機森林分類方法對鎖機制的選擇進行了推薦分析,其中使用剪枝操作主要考慮到鎖機制數據數量較大,進而造成的決策樹過于龐大的問題;使用加權操作主要考慮影響鎖機制選擇的特征屬性較多,相同權重的決策樹在分類效果上較低,不能保證最終結果的準確度。
由于決策樹采用自上而下、分而治之的學習策略,隨著迭代深度增加,節點所使用的訓練數據不斷減少,其對總體數據的代表性也會相對降低,導致無法對新數據進行合理的分析預測,即“過度擬合”現象[19]。決策樹剪枝是解決上述問題的一個有效途徑,其利用某種評價標準對決策樹進行簡化,減小規模,提高決策樹的泛化能力。本文選取后剪枝操作[20],后剪枝是指構造出完整的決策樹之后再去查看哪些子樹可以剪掉,從而能夠對未知數據有更準確的預測。
由于每棵樹訓練集不同,又互相獨立訓練,所以決策樹的分類精度會不同,加之受到樣本類別不平衡的影響,會進一步影響決策樹的分類效果,使得一些效果不好的樹投出錯誤的票數,從而影響隨機森林的分類能力。在隨機森林元分類器訓練的過程中,會隨機地抽取總訓練樣本中的部分數據對單個決策樹進行訓練,而未被抽取的數據稱為袋外(Out-Of-Bag,OOB)數據[21]。為了把較大的權重值分配給效果更好的分類器,本文采用OOB 估計計算分類器中的元分類器的投票權重,利用引入Kappa系數[22]對權重值進行進一步的計算,加權隨機森林算法如算法1 所示。利用袋外數據對決策樹進行的預測能力的評估就成為OOB 估計,在隨機森林構建的同時,每一個決策樹都會計算一個對應的OOB 數值。通過CK評價每棵決策樹整體分類效果,并根據CK給每棵決策樹分配投票權重,減少分類效果不好的決策樹對結果的影響,使算法的輸出結果更加合理,提高對數據集的整體分類性能。Kappa系數的計算方法如下所示:

其中:p0表示的是總分類準確度;pl表示某一類鎖機制的準確度,pl=(ai表示第i類真實樣本個數,bi表示第i類預測出來的樣本個數)。
算法1 結合Kappa系數的加權隨機森林算法。
輸入 訓練數據D,全部特征T,決策樹個數n,隨機森林模型RF;
輸出 加權的隨機森林模型。
1)遍歷RF中所有決策樹。
2)將數據集分為袋內數據和袋外數據。
3)計算整體OOB(D);選取特征變量i,隨機排序,計算OOB(Di)。
4)針對所有特征變量,重復步驟2)。
5)計算權重值W(i)為每一個特征變量OOB 的值減去整體OOB值的差乘以每棵決策樹的CK值。
6)將帶有權重的決策樹更新到RF輸出。
在算法1 中,W(i)越高,說明變量i越重要;如果W(i)=0,那么說明變量i重要性不大;如果W(i)<0,那么說明變量i有很明顯的噪聲,對模型產生了負面影響。利用特征重要性度量值作為特征排序的重要依據,依次從特征中去掉一個重要性最低的特征,并計算每次剔除后的分類正確率,選取最高正確率對應的特征變量作為最優特征選擇結果[23]。
在實現LockRec 時,設置決策樹數量、決策樹最大深度、分類數量以及樹的大小等數值分別為50、50、4、50,在剪枝算法中,設置的置信水平值越高則剪去的分支越少;值越低,剪去的分支越多,對于置信水平,通常將其值設置為0.25[24]。通過計算待剪枝決策樹T的所有葉節點的分類錯誤率上限,當前決策樹某葉節點對n個訓練樣本進行分類訓練,并且計算其對某個樣本分類錯誤的概率,從而求得該節點的分類錯誤率估計值,依據算法描述中的剪枝方法進行剪枝操作。在加權算法中,通過計算待加權的決策樹對袋外數據的分類效果,并且計算當前決策樹的CK 系數值,將兩者的乘積作為當前決策樹的權值。針對同步鎖、可重入鎖、讀寫鎖、郵戳鎖等四種鎖,使用上述模型構建一個鎖機制的推薦模型,當有一個新的待推薦并發程序時,首先獲取其對應上述兩種模型的特征屬性值,將待推薦數據進行10 次模型分類,統計這10 次中出現的推薦鎖機制,將次數最多的鎖機制作為最終鎖機制推薦的結果。
本文所有實驗在惠普Z820 工作站上完成的,硬件上,CPU 為Intel Xeon E5-2650 2.60 GHz兩個處理器,每個CPU 有8個處理核且均支持超線程,可以支持32線程同時運行,內存為128 GB。軟件上,使用了Deepin Linux 操作系統和軟件工具Eclipse 4.11,JDK版本為1.8.0_211。
為了驗證剪枝以及加權隨機森林的有效性,選取鎖機制數據集(lock)和另外4 個不同的數據集(來自UCI 的公開數據集,http://archive.ics.uci.edu/ml/datasets),進行了模型準確率、召回率等指標的驗證。數據集有關信息如表2所示。

表2 實驗中使用的數據集Tab.2 UCI datasets used in experiments
對于LockRec 中所使用的決策樹參數以及模型相關的評價指標如下:
1)決策樹有關參數。分別統計傳統隨機森林與改進的兩種隨機森林模型,決策樹個數在5~100 內變化時模型的準確率,這里對應的最大深度與決策樹大小與當前決策樹的個數相同。
2)運行次數。對于同一個數據集,在同一決策樹個數的情況下,重復構建5 次模型,并得到當前情況下的準確率的平均值。
3)評價指標。準確率(Precision,P)、召回率(Recall,R)、平均絕對誤差(Mean Absolute Error,MAE)和均方根誤差(Root Mean Squared Error,RMSE)的計算式如下:


其中:真陽性(True Positive,TP)表示樣本的真實類別是正例,并且模型預測的結果也是正例;真陰性(True Negative,TN)表示樣本的真實類別是負例,并且模型將其預測成為負例;假陽性(False Positive,FP)表示樣本的真實類別是負例,但是模型將其預測成為正例;假陰性(False Negative,FN)表示樣本的真實類別是正例,但是模型將其預測成為負例yi為預測值減去真實值。MAE值越小表示推薦系統的推薦精度越高,同樣RMSE值越小也表示推薦系統的推薦精度越高。
為了驗證所提出的模型適用性,本文使用了iris、breast、wine 和glass 四個數據集分別對不進行剪枝與加權操作的傳統模型和LockRec模型進行準確率驗證。
從圖7的對比可以看出,對于iris和breast數據集,所提出的LockRec 模型在決策樹數量較少時波動大,預測準確率有時相較傳統模型要較小,隨著決策樹個數的增加,準確率穩定提高,預測準確率均優于傳統模型,并且對iris 數據集LockRec 的準確率最后較為穩定,在92%左右,對breast 數據集則為86%左右。

圖7 iris和breast數據集上不同決策樹個數的模型準確率對比Fig.7 Accuracy comparison of models with different numbers of decision trees on iris and breast datasets
在圖8 中,對于wine 數據集,所提出的LockRec 模型在決策樹數量較少時與傳統模型預測準確率幾近一致,隨著決策樹個數的增加,兩個模型準確率均穩步提高,對wine 數據集LockRec 的準確率最后較為穩定在98%左右;對于glass 數據集,LockRec 的準確率一直高于傳統模型,并且在決策樹數量為30時,就達到了穩定,準確率為99%。

圖8 wine和glass數據集上不同決策樹個數的模型準確率對比Fig.8 Accuray comparison of models with different numbers of decision trees on wine and glass datasets
為了驗證提出的模型對于鎖機制數據的推薦合理性,對于鎖機制的數據集,實驗還選取推薦系統中常用的如召回率、平均絕對誤差(MAE)、均方根誤差(RMSE)等評價指標對LockRec進行了進一步的驗證。
圖9 是針對鎖機制數據集的兩種模型的對比,可以看到,傳統模型在決策樹個數較少時其準確率不高,隨著個數的增加,其準確率穩定在85%左右。對比準確率,LockRec 模型即使在決策樹個數較小時也呈現出了比較好的效果,并且隨著決策樹個數的增加,LockRec 模型的準確率很快穩定95%以上。對比召回率,在決策樹個數較少時,兩者召回率相近,均隨著決策樹個數的增加兩種模型均趨于直線上漲,兩個模型召回率最后分別穩定在82%和70%,說明LockRec 模型要更優于傳統模型。

圖9 不同決策樹個數的針對鎖機制數據集的兩種模型的準確率及召回率Fig.9 Accuracy and recall rate of two models with different numbers of decision trees for lock mechanism dataset
由圖10 可以看出,無論MAE 值還是RMSE 值,隨著決策樹數量的增加,傳統模型與LockRec 模型都呈現直線下降的趨勢,并且LockRec 模型的下降幅度要大于傳統模型。兩個模型MAE 最后分別穩定在0.53 和0.83,RMSE 分別穩定在0.7 和1.2。LockRec 模型的MAE 值和RMSE 值都更小,表明LockRec模型的預測精度要更高。

圖10 不同決策樹個數的針對鎖機制數據集的兩種模型的MAE值及RMSE值Fig.10 MAE and RMSE of two models with different numbers of decision trees for lock mechanism dataset
為了驗證模型對其他非Java 語言的鎖機制的適用性,選取了Python 語言中的鎖機制進行了程序信息收集,并使用LockRec 模型對其進行訓練預測,得到結果如圖11 所示。從圖11 的對比可以看出,對于Python 的鎖機制數據集,所提出的LockRec 模型在決策樹數量較少時與傳統模型準確率相近,在決策樹數量為25~35 時預測準確率相比傳統模型要較小,但隨著決策樹個數的增加,在決策樹數量35 個之后,其準確率穩定提高,預測準確率均優于傳統模型。

圖11 對于Python的鎖機制數據集不同決策樹個數的模型準確率對比Fig.11 Accuracy comparison of models with different numbers of decision trees for lock mechanism dataset of Python
綜上所述,本文所提出的LockRec 模型在對鎖機制數據集進行分析預測時有著比其他數據集更好的效果,并且所得到數值結果表明LockRec 模型不論是在準確率還是其他指標上,都要優于傳統模型。
使用LockRec 對Xalan(http://xalan.apache.org/xalan-j/)、Fop(https://xmlgraphics.apache.org/fop/)進行鎖機制使用推薦,其中Xalan 和Fop 分別有51 個和25 個使用鎖的方法。使用LockRec進行鎖機制推薦結果如圖12所示。

圖12 LockRec推薦結果Fig.12 Recommendation results of LockRec
可以看到,對于Xalan 使用LockRec 之后,推薦仍使用同步鎖的有30 個,推薦使用可重入鎖的有10 個、使用讀寫鎖的7 個、使用郵戳鎖的有4 個;對于Fop 中原始使用同步鎖的25個方法,使用LockRec 之后,推薦仍使用同步鎖的有10 個,推薦使用可重入鎖的有8 個、使用讀寫鎖的4 個、使用郵戳鎖的有3個。根據上述推薦結果,本文對Xalan、Fop 兩個程序進行了手動重構,并分析使用原鎖機制與推薦鎖機制的前后程序執行時間。這里使用不同個數的線程去執行重構前后的程序,每個線程數下均執行五次,最后取五次執行時間的平均值作為當前線程數的執行時間。
如圖13(a)所示,對于Xalan 來說,使用LockRec 推薦使用的鎖機制后,在不同執行線程數時,程序整體執行時間均有所縮短。程序整體平均縮短時間為127.65 s,當執行線程數為195 時,縮短時間最多為222 s,平均加速比為1.35;如圖13(b)所示,對于Fop 來說,使用LockRec 推薦使用的鎖機制后,在不同執行線程數時,程序整體執行時間均有所縮短。程序整體平均縮短時間為70.75 s,當執行線程數為200時,縮短時間最多為180 s,平均加速比為1.29。

圖13 LockRec推薦前后性能對比Fig.13 Comparison of performance before and after LockRec recommendation
實驗中有幾個可能威脅有效性的因素:1)由于并發程序執行的不確定性,不排除性能測試實驗結果可能存在細微偏差。為了避免誤差,所有實驗結果都是在5 次運行的基礎上取平均值得到的。2)隨機森林模型的構建依賴測試數據的好壞,為了驗證模型的適用性,本文選取多個著名數據集對所提出的改進隨機森林模型進行了驗證。3)本實驗只選取了2 個真實應用程序對LockRec 進行了評估,它們并不能代表所有程序,不能完全說明LockRec 在所有的應用程序中可以進行效果良好的推薦,未來的工作中也將使用更多應用程序對LockRec進行測試。
當程序員開發并發程序時,鎖是最常使用的一種同步機制,而使用哪個鎖作為最佳選擇是一個大問題,因為使用不同鎖構造的性能會有很大的不同。本文實現了一個鎖機制使用推薦的方法LockRec,可以幫助程序開發者選出當前程序代碼的最合適的鎖機制進行使用。在設計和實現LockRec 的過程中,使用兩種改進的隨機森林模型,并且結合實際測試以及真實程序進一步確保最終推薦結果的可信程度。實驗結果表明,LockRec 的推薦效率較為高效,模型推薦準確率平均值可達95.1%,使用推薦后的鎖機制,兩個真實程序性能均有所提高,平均加速比分別為1.35、1.29。在未來的工作中,將針對推薦方法進行進一步的研究,使用可以體現程序間關系的代碼推薦方法來提高鎖機制推薦使用的適用性。