2012-08-24 5 views
6

Mam następujący kod:Dziwne zachowanie z współbieżności w Haskell

import Control.Concurrent 

sleepSort = mapM_ (forkIO . put) 
    where put x = threadDelay (x*10000) >> print x 

ten wykonuje coś w rodzaju snu na zbiór liczb całkowitych, i działa dobrze, poza jednym zastrzeżeniem:

program wypisuje out każda z liczb w zestawie danych w kolejności, tak jak powinna. Jednak po zakończeniu drukowania ostatniego numeru czeka na wpisanie przez użytkownika pewnej liczby, a następnie echa, które cofają, a następnie kończą.

Nie sądzę, że w dowolnym momencie pytam o dane wprowadzone przez użytkownika, więc dlaczego tak się dzieje?

+0

Czy używasz GHCi? Jeśli tak, czy może to być po prostu dziwaczne działanie w sposób, który wydaje się, że zabiera i echa liczby? Jeśli nie, jak wygląda twój "główny"? – gspr

+0

Jeśli próbujesz to w GHCi, spróbuj wpisać "print" jako dane wejściowe użytkownika. – Vitus

Odpowiedz

7

Dzieje się tak, ponieważ główny wątek nie czeka na ukończenie innych wątków. Twój program rozpoczyna wątki, ale główny wątek natychmiast się kończy, a ty wracasz do pytania tłumacza. Tymczasem inne wątki nadal produkować wyjście:

Prelude Control.Concurrent> sleepSort [1,2,3] 
1 
Prelude Control.Concurrent> 2 
3 

Można rozwiązać ten problem poprzez dodanie opóźnienia do głównego wątku:

Prelude Control.Concurrent> sleepSort [1,2,3] >> threadDelay 10000 
1 
2 
3 

Jeśli biegały skompilowany program to po prostu wyjść natychmiast, bez drukowanie coś:

$ cat Test.hs 
import Control.Concurrent 

sleepSort = mapM_ (forkIO . put) 
    where put x = threadDelay (x*1000) >> print x 

main = sleepSort [1,2,3] 
$ ghc --make -O2 Test.hs 
[1 of 1] Compiling Main    (Test.hs, Test.o) 
Linking Test ... 
$ ./Test 
$ 

Aktualizacja: Zamiast dodawać wezwanie do threadDelay do main, możesz użyć semafora w funkcji sleepSort:

+0

Czy istnieje prosty sposób oczekiwania na ukończenie innych wątków, czy może to skomplikować? –

+1

@BenjaminKovach Zobacz aktualizację. –

+0

Dziękuję bardzo! –