-
Notifications
You must be signed in to change notification settings - Fork 104
/
geturlsfirst.hs
96 lines (78 loc) · 1.97 KB
/
geturlsfirst.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
{-# LANGUAGE CPP #-}
-- STM Async API used in \secref{stm-async}
module Main where
import GetURL
#if __GLASGOW_HASKELL__ < 706
import ConcurrentUtils (forkFinally)
#endif
import Control.Concurrent
import Control.Exception
import Control.Concurrent.STM
import Text.Printf
import qualified Data.ByteString as B
-- -----------------------------------------------------------------------------
-- STM Async API
-- <<Async
data Async a = Async ThreadId (TMVar (Either SomeException a))
-- >>
-- <<async
async :: IO a -> IO (Async a)
async action = do
var <- newEmptyTMVarIO
t <- forkFinally action (atomically . putTMVar var)
return (Async t var)
-- >>
--- <<watchCatch
waitCatch :: Async a -> IO (Either SomeException a)
waitCatch = atomically . waitCatchSTM
-- >>
-- <<waitCatchSTM
waitCatchSTM :: Async a -> STM (Either SomeException a)
waitCatchSTM (Async _ var) = readTMVar var
-- >>
-- <<waitSTM
waitSTM :: Async a -> STM a
waitSTM a = do
r <- waitCatchSTM a
case r of
Left e -> throwSTM e
Right a -> return a
-- >>
-- <<wait
wait :: Async a -> IO a
wait = atomically . waitSTM
-- >>
-- <<cancel
cancel :: Async a -> IO ()
cancel (Async t _) = throwTo t ThreadKilled
-- >>
-- <<waitEither
waitEither :: Async a -> Async b -> IO (Either a b)
waitEither a b = atomically $
fmap Left (waitSTM a)
`orElse`
fmap Right (waitSTM b)
-- >>
-- <<waitAny
waitAny :: [Async a] -> IO a
waitAny asyncs =
atomically $ foldr orElse retry $ map waitSTM asyncs
-- >>
-----------------------------------------------------------------------------
sites = ["http://www.google.com",
"http://www.bing.com",
"http://www.yahoo.com",
"http://www.wikipedia.com/wiki/Spade",
"http://www.wikipedia.com/wiki/Shovel"]
-- <<main
main :: IO ()
main = do
let
download url = do
r <- getURL url
return (url, r)
as <- mapM (async . download) sites
(url, r) <- waitAny as
printf "%s was first (%d bytes)\n" url (B.length r)
mapM_ wait as
-- >>