Haskell Language
संगामिति
खोज…
टिप्पणियों
हास्केल में समवर्ती और समानांतर प्रोग्रामिंग के बारे में सीखने के लिए अच्छे संसाधन हैं:
`ForkIO` के साथ स्प्रेडिंग थ्रेड्स
हास्केल forkIO
कई रूपों का समर्थन करता है और सबसे स्पष्ट है कि forkIO
का उपयोग करके एक थ्रेड forkIO
।
फ़ंक्शन forkIO :: IO () -> IO ThreadId
एक IO
एक्शन लेता है और अपने ThreadId
, इस बीच ThreadId
में एक्शन चलाया जाएगा।
हम इसे पूरी तरह से ghci
का उपयोग करके प्रदर्शित कर सकते हैं:
Prelude Control.Concurrent> forkIO $ (print . sum) [1..100000000]
ThreadId 290
Prelude Control.Concurrent> forkIO $ print "hi!"
"hi!"
-- some time later....
Prelude Control.Concurrent> 50000005000000
दोनों क्रियाएं पृष्ठभूमि में चलेंगी, और दूसरा अंतिम से पहले समाप्त होने की गारंटी है!
`एमवीआर` के साथ थ्रेड्स के बीच संचार
MVar a
का उपयोग करते हुए थ्रेड्स के बीच जानकारी को पास करना बहुत आसान है और Control.Concurrent
में इसके साथ काम करता है। MVar a
:
-
newEmptyMVar :: IO (MVar a)
- एक नयाMVar a
बनाताMVar a
-
newMVar :: a -> IO (MVar a)
- दिए गए मान के साथ एक नयाMVar
बनाता है -
takeMVar :: MVar a -> IO a
- दिए गएMVar
से मान प्राप्त करता है, या एक उपलब्ध होने तक ब्लॉक करता है -
putMVar :: MVar a -> a -> IO ()
- दिए गए मूल्य कोMVar
में डालता है, या खाली होने तक ब्लॉक करता है
आइए एक सूत्र में 1 से 100 मिलियन तक की संख्या प्राप्त करें और परिणाम पर प्रतीक्षा करें:
import Control.Concurrent
main = do
m <- newEmptyMVar
forkIO $ putMVar m $ sum [1..10000000]
print =<< takeMVar m -- takeMVar will block 'til m is non-empty!
अधिक इनपुट के लिए प्रतीक्षा करते समय पृष्ठभूमि में उपयोगकर्ता इनपुट और योग लेने के लिए एक अधिक जटिल प्रदर्शन हो सकता है:
main2 = loop
where
loop = do
m <- newEmptyMVar
n <- getLine
putStrLn "Calculating. Please wait"
-- In another thread, parse the user input and sum
forkIO $ putMVar m $ sum [1..(read n :: Int)]
-- In another thread, wait 'til the sum's complete then print it
forkIO $ print =<< takeMVar m
loop
जैसा कि पहले कहा गया है, यदि आप takeMVar
कहते हैं और MVar
खाली है, तो यह तब तक ब्लॉक होता है जब तक कि एक और धागा MVar
में कुछ डाल नहीं MVar
, जिसके परिणामस्वरूप डाइनिंग फिलॉसॉफ़र्स समस्या हो सकती है । यही बात putMVar
साथ putMVar
: अगर यह भरा हुआ है, तो यह खाली हो जाएगा!
निम्नलिखित कार्य करें:
concurrent ma mb = do
a <- takeMVar ma
b <- takeMVar mb
putMVar ma a
putMVar mb b
हम दो कार्यों को कुछ MVar
साथ MVar
concurrent ma mb -- new thread 1
concurrent mb ma -- new thread 2
क्या हो सकता है:
- थ्रेड 1 पढ़ता
ma
और ब्लॉकma
- थ्रेड 2 पढ़ता है
mb
और इस प्रकारmb
ब्लॉक करता है
अब थ्रेड 1 mb
को नहीं पढ़ सकता क्योंकि थ्रेड 2 ने इसे ब्लॉक कर दिया है, और थ्रेड 2 ma
को नहीं पढ़ सकता क्योंकि थ्रेड 1 ने इसे ब्लॉक कर दिया है। एक क्लासिक गतिरोध!
सॉफ्टवेयर ट्रांजैक्शनल मेमोरी के साथ परमाणु ब्लॉक
हास्केल में एक और शक्तिशाली और परिपक्व संगामिति उपकरण है सॉफ्टवेयर ट्रांजैक्शनल मेमोरी, जो कई थ्रेड्स के लिए TVar a
ही चर में एक परमाणु तरीके से लिखने की अनुमति देता है।
TVar a
मुख्य प्रकार है जो STM
TVar a
जुड़ा होता है और इसका मतलब होता है लेन-देन चर। वे MVar
तरह उपयोग किए जाते हैं, लेकिन निम्नलिखित कार्यों के माध्यम से STM
MVar
भीतर:
atomically :: STM a -> IO a
एसटीएम क्रियाओं की एक श्रृंखला को परमाणु रूप से निष्पादित करें।
readTVar :: TVar a -> STM a
TVar
का मान पढ़ें, जैसे:
value <- readTVar t
writeTVar :: TVar a -> a -> STM ()
दिए गए TVar
मान लिखें।
t <- newTVar Nothing writeTVar t (Just "Hello")
यह उदाहरण हास्केल विकी से लिया गया है:
import Control.Monad import Control.Concurrent import Control.Concurrent.STM main = do -- Initialise a new TVar shared <- atomically $ newTVar 0 -- Read the value before <- atomRead shared putStrLn $ "Before: " ++ show before forkIO $ 25 `timesDo` (dispVar shared >> milliSleep 20) forkIO $ 10 `timesDo` (appV ((+) 2) shared >> milliSleep 50) forkIO $ 20 `timesDo` (appV pred shared >> milliSleep 25) milliSleep 800 after <- atomRead shared putStrLn $ "After: " ++ show after where timesDo = replicateM_ milliSleep = threadDelay . (*) 1000 atomRead = atomically . readTVar dispVar x = atomRead x >>= print appV fn x = atomically $ readTVar x >>= writeTVar x . fn