Как использовать многопоточность в Haskell?

Пользователь

от rachel , в категории: Другие , год назад

Как использовать многопоточность в Haskell?

Facebook Vk Ok Twitter LinkedIn Telegram Whatsapp

1 ответ

Пользователь

от nikko , год назад

@rachel 

В Haskell многопоточность может быть реализована с помощью библиотеки Control.Concurrent. Можно создавать новые потоки с помощью функции forkIO. Например, чтобы создать новый поток, который выполняет функцию f, можно использовать следующий код:

1
2
3
4
5
6
7
import Control.Concurrent

main :: IO ()
main = do
    forkIO f
    putStrLn "Main thread"
    -- другие действия


Также можно использовать примитивы синхронизации, такие как MVar и STM. Например, следующий код показывает, как использовать MVar для синхронизации двух потоков:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import Control.Concurrent

main :: IO ()
main = do
    mvar <- newEmptyMVar
    forkIO $ do
        putStrLn "Thread 1"
        putMVar mvar ()
    takeMVar mvar
    putStrLn "Main thread"


В этом примере, поток 1 выводит сообщение на консоль и затем помещает значение в MVar. Поток main вызывает функцию takeMVar, которая заблокируется до тех пор, пока значение не будет доступно в MVar. Когда значение будет доступно, поток main выведет сообщение на консоль.


STM (Software Transactional Memory) предоставляет более мощный механизм для синхронизации потоков в Haskell. STM позволяет описывать транзакции, которые могут быть выполнены атомарно. Пример использования STM:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import Control.Concurrent
import Control.Concurrent.STM

main :: IO ()
main = do
    account <- newTVarIO 100
    forkIO $ atomically $ do
        balance <- readTVar account
        writeTVar account (balance - 50)
        putStrLn "Thread 1"
    forkIO $ atomically $ do
        balance <- readTVar account
        writeTVar account (balance - 75)
        putStrLn "Thread 2"
    threadDelay 1000000 -- пауза в главном потоке
    balance <- readTVarIO account
    putStrLn $ "Balance: " ++ show balance


В этом примере создаются два потока, каждый из которых изменяет значение в TVar и выводит сообщение на консоль. Затем главный поток ожидает 1 секунду (с помощью функции threadDelay) и выводит текущий баланс, который был изменен другими потоками. Функция atomically гарантирует, что все операции с TVar выполнены атомарно.