2011-06-22 10 views
19

के साथ खराब प्रदर्शन/लॉकअप मैं एक प्रोग्राम लिख रहा हूं जहां बड़ी संख्या में एजेंट घटनाओं को सुनते हैं और उन पर प्रतिक्रिया करते हैं। Control.Concurrent.Chan.dupChan के बाद से हटा दिया गया है मैं Tchan के रूप में विज्ञापित उपयोग करने का फैसला।एसटीएम

टीसीएचएन का प्रदर्शन मेरी अपेक्षा से भी बदतर है। मैं निम्नलिखित प्रोग्राम है जो मुद्दे को दर्शाता है:

{-# LANGUAGE BangPatterns #-} 

module Main where 

import Control.Concurrent.STM 
import Control.Concurrent 
import System.Random(randomRIO) 
import Control.Monad(forever, when) 

allCoords :: [(Int,Int)] 
allCoords = [(x,y) | x <- [0..99], y <- [0..99]] 

randomCoords :: IO (Int,Int) 
randomCoords = do 
    x <- randomRIO (0,99) 
    y <- randomRIO (0,99) 
    return (x,y) 

main = do 
    chan <- newTChanIO :: IO (TChan ((Int,Int),Int)) 

    let watcher p = do 
     chan' <- atomically $ dupTChan chan 
     forkIO $ forever $ do 
        [email protected](p',_counter) <- atomically $ readTChan chan' 
        when (p == p') (print r) 
     return() 

    mapM_ watcher allCoords 

    let go !cnt = do 
     xy <- randomCoords 
     atomically $ writeTChan chan (xy,cnt) 
     go (cnt+1) 

    go 1 

जब संकलित (-O) और इस तरह कार्यक्रम पहले इच्छा उत्पादन कुछ चलाएँ:

 
./tchantest 
((0,25),341) 
((0,33),523) 
((0,33),654) 
((0,35),196) 
((0,48),181) 
((0,48),446) 
((1,15),676) 
((1,50),260) 
((1,78),561) 
((2,30),622) 
((2,38),383) 
((2,41),365) 
((2,50),596) 
((2,57),194) 
((3,19),259) 
((3,27),344) 
((3,33),65) 
((3,37),124) 
((3,49),109) 
((3,72),91) 
((3,87),637) 
((3,96),14) 
((4,0),34) 
((4,17),390) 
((4,73),381) 
((4,74),217) 
((4,78),150) 
((5,7),476) 
((5,27),207) 
((5,47),197) 
((5,49),543) 
((5,53),641) 
((5,58),175) 
((5,70),497) 
((5,88),421) 
((5,89),617) 
((6,0),15) 
((6,4),322) 
((6,16),661) 
((6,18),405) 
((6,30),526) 
((6,50),183) 
((6,61),528) 
((7,0),74) 
((7,28),479) 
((7,66),418) 
((7,72),318) 
((7,79),101) 
((7,84),462) 
((7,98),669) 
((8,5),126) 
((8,64),113) 
((8,77),154) 
((8,83),265) 
((9,4),253) 
((9,26),220) 
((9,41),255) 
((9,63),51) 
((9,64),229) 
((9,73),621) 
((9,76),384) 
((9,92),569) 
... 

और फिर, कुछ बिंदु पर, बंद हो जाएगा कुछ भी लिखना, जबकि अभी भी 100% सीपीयू खपत है।

 
((20,56),186) 
((20,58),558) 
((20,68),277) 
((20,76),102) 
((21,5),396) 
((21,7),84) 

लॉकअप के साथ-साथ भी तेज है और केवल कुछ मुट्ठी भर के बाद होता है। यह आरटीएस '-एन ध्वज के माध्यम से जो भी कोर उपलब्ध कराया जाएगा, वह भी उपभोग करेगा।

इसके अतिरिक्त प्रदर्शन खराब दिखता है - केवल प्रति सेकंड लगभग 100 ईवेंट संसाधित होते हैं।

क्या यह एसटीएम में एक बग है या क्या मैं एसटीएम के अर्थशास्त्र के बारे में कुछ गलत समझ रहा हूं?

+3

एक चीज जिसे आप गलत समझते हैं वह यह है कि 'चान' एक पाठक को जगाएगा जबकि एसटीएम का 'टीखान' सभी व्यक्तिगत पाठकों के लिए * सभी * पाठकों को जगाएगा। इसके अलावा, नील ब्राउन के जवाब में आपके लिए एक अच्छा सुझाव है। –

+1

यह एसटीएम का अर्थशास्त्र नहीं है जिसे आप गलत समझते हैं, यह कार्यान्वयन है। यह आशावादी लॉकिंग के साथ लागू किया गया है। यह उन मामलों में उचित बनाता है जहां आपके पास कई स्वतंत्र म्यूटेबल सेल हैं और कई लेन-देन जो आमतौर पर अपडेट नहीं करना चाहते हैं-उनमें से गैर-ओवरलैपिंग सबसेट्स। यह उस मामले में बहुत अनुचित बनाता है जहां हर लेनदेन एक ही परिवर्तनीय सेल को छूता है - इस मामले में टीसीएचएन की तरह। – Carl

+1

यहां तक ​​कि जहां भी प्रत्येक लेन-देन एक ही परिवर्तनीय सेल को छूता है, तब तक जब तक पर्याप्त रूप से लिखने वाले लिखते हैं, तब तक आप बहुत अच्छी तरह से कर सकते हैं। – sclv

उत्तर

21

कार्यक्रम काफी बुरी तरह से प्रदर्शन करने जा रहा है। आप 10,000 धागे जो सभी के लिए लिखा जा के लिए एक एकल Tvar के लिए इंतजार अप कतार होगा बंद को उत्पन्न करने जा रहे हैं। तो एक बार वे सब जा रहे हैं, आप अच्छी तरह से हो रहा प्राप्त कर सकते हैं:

  1. 10.000 धागे की प्रत्येक चैनल से पढ़ने के लिए कोशिश करता है, यह खाली पाता है, और अंतर्निहित Tvar के लिए प्रतीक्षा कतार में ही कहते हैं। तो आपके पास टीवी कतार के लिए प्रतीक्षा कतार में 10,000 कतार-अप घटनाएं और 10,000 प्रक्रियाएं होंगी।
  2. कुछ चैनल के लिए लिखा है। यह 10,000 धागे से प्रत्येक unqueue और रन-कतार पर इसे वापस डाल देंगे (इस हे हो सकता है (एन) या हे (1), कैसे आरटीएस लिखा है के आधार पर)।
  3. 10,000 धागे से प्रत्येक फिर आइटम पर कार्रवाई करता है, तो यह उस में रुचि रखते हैं, जो सबसे अधिक नहीं होगा यह देखने के लिए चाहिए।

इसलिए प्रत्येक आइटम ओ (10,000) प्रसंस्करण का कारण बन जाएगा। आप इसका मतलब है कि प्रत्येक थ्रेड को जगाने के लिए के बारे में 1 माइक्रोसेकंड की आवश्यकता है प्रति सेकंड 100 घटनाओं, देखते हैं, तो, TVars के एक जोड़े को पढ़ने के एक करने के लिए लिख सकते हैं और फिर से कतार। यह इतना अनुचित नहीं लगता है। मुझे समझ में नहीं आता कि कार्यक्रम पूरी तरह से बंद क्यों होगा।

सामान्य तौर पर, मैं इस डिजाइन स्क्रैप और इसे बदलना इस प्रकार हैं:

किसी एकल थ्रेड घटना चैनल है, जो एक मानचित्र का कहना रुचि रिसीवर चैनल को समन्वय से पढ़ लो। एकल धागा ओ (लॉग एन) समय में मानचित्र से रिसीवर (ओं) को चुन सकता है (ओ (एन) से काफी बेहतर है, और इसमें बहुत छोटे स्थिर कारक शामिल हैं), और केवल रुचि प्राप्तकर्ता को ईवेंट भेजें । तो आप रुचि रखने वाले पार्टी को केवल एक या दो संचार करते हैं, बजाय हर किसी के लिए 10,000 संचार। विचार 5 का एक सूची-आधारित रूप सीएचपी में लिखा गया है।इस पत्र के 4: http://chplib.files.wordpress.com/2011/05/chp.pdf

6

क्या नील ने कहा करने के लिए जोड़ा जा रहा है, अपने कोड भी एक अंतरिक्ष रिसाव (के साथ छोटे n ध्यान देने योग्य है): स्पष्ट टपल का निर्माण हुआ मुद्दा by making tuples strict फिक्सिंग के बाद Space leak, मैं निम्नलिखित प्रोफाइल के साथ छोड़ दिया गया था: Profile with strict tuples यहां क्या हो रहा है, मुझे लगता है कि, मुख्य धागा साझा TChan पर डेटा लिख ​​रहा है, कार्यकर्ता थ्रेड इसे पढ़ सकते हैं (TChan, जैसे Chan, असंबद्ध है)। तो कार्यकर्ता धागे spend most of their time अपने संबंधित एसटीएम लेनदेन को दोबारा बेचते हुए, जबकि मुख्य धागा चैनल में और भी डेटा भरने में व्यस्त है; यह बताता है कि आपका प्रोग्राम क्यों लटकता है।

+4

इस समस्या का एक समाधान एक बाउंडेड टीसीएचएन का उपयोग कर रहा है। मैंने कुछ समय पहले विकसित किया था और इसे पैकेज [बाध्य-tchan] (http://hackage.haskell.org/package/bounded-tchan) के रूप में रिलीज़ किया था, लेकिन इन दिनों आप वेरेन के भयानक और अधिक पूर्ण पैकेज का उपयोग करना चाहेंगे [ एसटीएम-चान्स] (http://hackage.haskell.org/package/stm-chans) (विशेष रूप से, 'Control.Concurrent.STM.TBChan')। –

+0

ठीक है, मैंने आपके उत्तर को सावधानीपूर्वक पर्याप्त नहीं पढ़ा, इस प्रकार आप नहीं देखते थे कि आप ट्यूपल के मूल्यांकन के बारे में बात कर रहे थे और कभी भी बढ़ते एसटीएम टीसीएचएन नहीं थे। मैं अपनी पिछली टिप्पणी छोड़ दूंगा क्योंकि बाध्य चैन उपयोगी हैं, लेकिन मुझे एहसास है कि यह ऑफ-मार्क है। –

+0

@ थॉमस मैं दोनों के बारे में बात कर रहा था। या शायद मैंने इसे संपादित करने से पहले अपना जवाब पढ़ा। –

9

यह एक अच्छा परीक्षण मामला है! मुझे लगता है कि आपने वास्तव में वास्तविक livelock/भुखमरी का एक दुर्लभ उदाहरण बनाया है। हम -eventlog के साथ संकलित करके और -vst के साथ चलकर या -debug के साथ संकलित करके -Ds के साथ चलकर इसका परीक्षण कर सकते हैं। हम देखते हैं कि प्रोग्राम रनटाइम "लटका" के रूप में भी अभी भी पागल की तरह काम कर रहा है, अवरुद्ध धागे के बीच कूद रहा है।

उच्च स्तरीय कारण यह है कि आपके पास एक (तेज़) लेखक और कई (तेज़) पाठक हैं। पाठकों और लेखक दोनों को कतार के अंत का प्रतिनिधित्व करने वाले एक ही टीवीर तक पहुंचने की आवश्यकता है। आइए मान लें कि नोडेटर्मिनिस्टिक रूप से एक धागा सफल होता है और जब ऐसा होता है तो अन्य सभी विफल हो जाते हैं। अब, जब हम 100 * 100 तक विवाद में धागे की संख्या बढ़ाते हैं, तो पाठक की प्रगति की संभावना तेजी से शून्य की ओर जाती है। इस बीच, लेखक वास्तव में लंबे को पाठकों की तुलना में उस टीवीर की पहुंच में लेते हैं, जिससे चीजों को इसके लिए और भी बदतर बना दिया जाता है।

इस उदाहरण में, लेखक के लिए go के प्रत्येक आमंत्रण के बीच एक छोटा थ्रॉटल डालना (कहें, threadDelay 100) समस्या को ठीक करने के लिए पर्याप्त है। यह पाठकों को लगातार लिखने के बीच सभी ब्लॉक के लिए पर्याप्त समय देता है, और इसलिए livelock को समाप्त करता है। हालांकि, मैं सोचता हूं कि इस तरह की स्थितियों से निपटने के लिए रनटाइम शेड्यूलर के व्यवहार को बेहतर बनाने में यह एक दिलचस्प समस्या होगी।

+1

रनटाइम शेड्यूलर एसटीएम कार्यों को समवर्ती रूप से निष्पादित करने के सामान्य मामले में इसका सामना नहीं कर सकता है। यह आशावादी लॉकिंग की प्रकृति है - यह विवाद के तहत खत्म हो जाती है। यह सैद्धांतिक रूप से नियंत्रित करने के अन्य तरीकों के साथ वैकल्पिक एसटीएम कार्यान्वयन प्रदान करने के लिए सैद्धांतिक रूप से संभव है। निराशावादी लॉकिंग इस मामले को इतनी मेहनत नहीं कर पाएगी। लेकिन उस दिशा में कोई वास्तविक प्रगति नहीं हुई है। – Carl

+1

@ करल - एक वैकल्पिक शेड्यूलर का उपयोग करने की संभावना है जिसमें अधिक परिष्कृत नीतियां हैं, जैसे घातीय बैकऑफ इत्यादि। आपको अभी भी दुर्भावनापूर्ण कोड में समस्या हो सकती है, लेकिन कम से कम स्पष्ट रूप से इस तरह के रोगजनक मामलों से बचा जा सकता है। – sclv

संबंधित मुद्दे