Mibori Shante — Google Node

Последние действия

Control.Process — Краткое введение

Понимание типов Proc msg val и Process msg, ссылки на процесс, процедуры и очереди сообщений
  • Proc msg val — это аналог типа IO val, но с типом сообщений msg. Это IO-действие возвращающая результат типа val и возможностью принимать сообщение типа msg. Для краткости будем такие действия называть процедурами.
  • Process msg — это аналог типа ThreadId, представляющий из себя ссылку на запущенную параллельно процедуру. Для краткости будем называть ссылкой на процесс или просто процесс. Одна процедура способна отправлять другой процедуре сообщения по его ссылке. Сообщение при этом попадает в очередь сообщений той процедуры, куда она отправлена. Ссылка на процесс всегда типизирована типом сообщений, которые может принимать работающая по ссылке процедура.

Как использовать IO-функции
Разумеется, поскольку процедуры
это такие же IO-действия их можно использовать абсолютно так же.
Например, функции main1 и main2 в следующем примере выполняют одно и тоже:

main1 :: IO ()
main1 = f1

f1 :: IO ()
f1 = do
    s <- getLine
    putStrLn ("Output: " ++ s)

main2 :: IO ()
main2 = action f2

f2 :: Proc () ()
f2 = do
    s <- liftIO getLine
    liftIO $ putStrLn ("Output: " ++ s)



Порождение процессов

Для того, чтобы создать процесс из процедуры требуется процедура spawn:

spawn :: Proc remoteMsg () -> Proc msg (Process remoteMsg)

spawn p создает некоторый процесс из процедуры p и возвращает на него ссылку link:

do  ...
    link <- spawn p
    ...


Завершение процессов

Чтобы завершить процесс, нужно знать ссылку на него. Процесс завершается при помощи процедуры kill:

kill :: Process remoteMsg -> Proc msg ()

kill link завершает процесс по ссылке link.
Следующий пример выводит сообщение "Hello world" только пять секунд, затем выводящий процесс убивается:

loop :: Proc () ()
loop = do
    liftIO $ putStrLn "Hello world"
    loop            -- бесконечный цикл

f :: Proc () ()
f = do
    p <- spawn loop -- создать процесс из loop
    delay 5000000   -- подождать пять секунд
    kill p          -- прибить процесс

start :: IO ()
start = action f


delay microseconds
— ожидание в микросекундах


Отправка сообщений

Для отправки сообщения процессу нужно знать ссылку на него. Ссылка должна быть типизирована типом сообщения, которое может принять процедура, которой отправляется сообщение. Отправка делается процедурой send:

send :: Process remoteMsg -> remoteMsg -> Proc msg ()

send link msg — отправляет сообщение msg процессу link.
Если тип сообщения не соответствует типу очереди сообщений процесса, то будет ошибка типизации на стадии компиляции.


Прием сообщений

Прием сообщений в текущей процедуре из очереди текущей процедуры
осуществляется при помощи recv:

recv :: Proc msg msg

recv ожидает, пока в очередь к текущей процедуре попадёт сообщение, и тут  же возвращает его
:

do  ...
    msg <- recv
    ...


Пример Counter
  • Протестировать можно в ghci.
  • При помощи startServer st запускается сервер с начальным стоянием st.
  • startServer возвращает ссылку link на процесс сервера.
  • При помощи inc link, dec link, set link val можно инкрементировать, декрементировать и просто устанваливать новое значение состояния сервера.
  • При помощи getVal link это стояние можно прочитать.
  • Завершить работу сервера можно через kill link.
Интерфейсные функции:
-- запустить сервер и получить ссылку на его процесс
startServer st = action $ spawn $ server st

-- инкремент состояния сервера
inc srv = sendIO srv Inc

-- декремент состояния сервера
dec srv = sendIO srv Dec

-- установить серверу состояние
set srv st = sendIO srv $ Value st

-- получить от сервера значение состояние
getVal srv = action $ do
me <- self
send srv $ GetValue me
recv
Протокол и серверная часть:
-- серверная часть принимает сообщения типа Server
data Server
= Inc -- инкремент состояния сервера
| Dec -- декремент состояния сервера
| GetValue (Process Integer)
-- получить состояние сервера
| Value Integer
-- установить состояние сервера
deriving Show

-- процедура сервера
server st = do
msg <- recv
liftIO $ putStrLn ("Server: msg = " ++ show msg)
case msg of
Inc -> server (st + 1)
Dec -> server (st - 1)
GetValue cli -> do
send cli st
server st
Value newSt -> server newSt

См. больше примеров в приложении к этой странице.


Что ещё

Приложения (5)