Hints on how to remove unsafePerformIO from my function?
I am writing a voip server to take advantage of haskells awesome threading and parsing ability. At first everything was going great, but my thread that fetches udp makes use of unsafePerformIO: fetchUDPSIP :: TChan B.ByteString -> IO () fetchUDPSIP chan = do sock <- getUDPSocket 5060 let results = (unstrict . repeat . getUDP) sock mapM_ (atomically . writeTChan chan) results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs It fetches it from a socket, and then writes it to a TChan. This results in a stream of bytestrings that another thread can read from. If I don't use unsafePerformIO, then it tries to read all possible packets before returning anything, and so it never writes to the TChan at all. The problem with doing it this way is that unsafePerformIO apparently stops every other thread from doing anything while it is waiting for a packet. But I can't think of a way to rewrite this function to do what I want. I'm kind of new to this, does anyone have any hints that could help me out? Here's a simple version without any of the implementation details: fetchLine = do let results = (unstrict . repeat) getLine mapM_ putStrLn results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
fork it into a thread and have it run on a loop, yielding if it can't read any data from the udp socket? On 19 July 2010 16:07, David McBride <dmcbride@neondsl.com> wrote:
I am writing a voip server to take advantage of haskells awesome threading and parsing ability. At first everything was going great, but my thread that fetches udp makes use of unsafePerformIO:
fetchUDPSIP :: TChan B.ByteString -> IO () fetchUDPSIP chan = do sock <- getUDPSocket 5060 let results = (unstrict . repeat . getUDP) sock mapM_ (atomically . writeTChan chan) results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
It fetches it from a socket, and then writes it to a TChan. This results in a stream of bytestrings that another thread can read from. If I don't use unsafePerformIO, then it tries to read all possible packets before returning anything, and so it never writes to the TChan at all. The problem with doing it this way is that unsafePerformIO apparently stops every other thread from doing anything while it is waiting for a packet.
But I can't think of a way to rewrite this function to do what I want. I'm kind of new to this, does anyone have any hints that could help me out?
Here's a simple version without any of the implementation details:
fetchLine = do let results = (unstrict . repeat) getLine mapM_ putStrLn results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
Well, I thought about that, but I can't find anything in the network.socket library that would allow me to see if there is any data ready to be read from. But besides that, wouldn't that cause a busy wait as the thread constantly failed to read and yielded over and over again until there was a new packet? I'd rather if this thread chilled out until something worthwhile occurs. On Mon, Jul 19, 2010 at 10:12 AM, Benjamin Edwards <edwards.benj@gmail.com>wrote:
fork it into a thread and have it run on a loop, yielding if it can't read any data from the udp socket?
On 19 July 2010 16:07, David McBride <dmcbride@neondsl.com> wrote:
I am writing a voip server to take advantage of haskells awesome threading and parsing ability. At first everything was going great, but my thread that fetches udp makes use of unsafePerformIO:
fetchUDPSIP :: TChan B.ByteString -> IO () fetchUDPSIP chan = do sock <- getUDPSocket 5060 let results = (unstrict . repeat . getUDP) sock mapM_ (atomically . writeTChan chan) results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
It fetches it from a socket, and then writes it to a TChan. This results in a stream of bytestrings that another thread can read from. If I don't use unsafePerformIO, then it tries to read all possible packets before returning anything, and so it never writes to the TChan at all. The problem with doing it this way is that unsafePerformIO apparently stops every other thread from doing anything while it is waiting for a packet.
But I can't think of a way to rewrite this function to do what I want. I'm kind of new to this, does anyone have any hints that could help me out?
Here's a simple version without any of the implementation details:
fetchLine = do let results = (unstrict . repeat) getLine mapM_ putStrLn results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
How about unsafeInterleaveIO? - You might have to experiment where to put it, but you shouldn't need the local unstrict definition. Because it doesn't violate type safety it is considered less heinous than unsafePerformIO.
I tried this: fetchUDPSIP :: TChan a -> TChan B.ByteString -> IO () fetchUDPSIP commands chan = do sock <- getUDPSocket 5060 results <- (mapM unsafeInterleaveIO . repeat . getUDP) sock mapM_ (atomically . writeTChan chan) results fetchLine = do results <- (mapM unsafeInterleaveIO . repeat) Prelude.getLine mapM_ Prelude.putStrLn results But it seems to have become strict again in that neither version will return any results until it has gotten everything it can. Also I'm not sure, but I'm pretty sure any "unsafe" function is still going to have the original problem where it causes all other threads to stop while it performs, so I don't think I can use unsafe anything at all and have my program work properly. On Mon, Jul 19, 2010 at 10:41 AM, Stephen Tetley <stephen.tetley@gmail.com>wrote:
How about unsafeInterleaveIO? - You might have to experiment where to put it, but you shouldn't need the local unstrict definition.
Because it doesn't violate type safety it is considered less heinous than unsafePerformIO. _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
Okay, I figured this out on my own. This isn't as elegant but it definitely works: fetchUDPSIP :: TChan a -> TChan B.ByteString -> IO () fetchUDPSIP commands chan = do sock <- getUDPSocket 5060 loop sock where loop sock = do result <- getUDP sock (atomically . writeTChan chan) result loop sock fetchLine = do loop where loop = do result <- Prelude.getLine Prelude.putStrLn result loop On Mon, Jul 19, 2010 at 11:09 AM, David McBride <dmcbride@neondsl.com>wrote:
I tried this:
fetchUDPSIP :: TChan a -> TChan B.ByteString -> IO () fetchUDPSIP commands chan = do sock <- getUDPSocket 5060 results <- (mapM unsafeInterleaveIO . repeat . getUDP) sock
mapM_ (atomically . writeTChan chan) results
fetchLine = do results <- (mapM unsafeInterleaveIO . repeat) Prelude.getLine mapM_ Prelude.putStrLn results
But it seems to have become strict again in that neither version will return any results until it has gotten everything it can.
Also I'm not sure, but I'm pretty sure any "unsafe" function is still going to have the original problem where it causes all other threads to stop while it performs, so I don't think I can use unsafe anything at all and have my program work properly.
On Mon, Jul 19, 2010 at 10:41 AM, Stephen Tetley <stephen.tetley@gmail.com
wrote:
How about unsafeInterleaveIO? - You might have to experiment where to put it, but you shouldn't need the local unstrict definition.
Because it doesn't violate type safety it is considered less heinous than unsafePerformIO. _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
On Mon, Jul 19, 2010 at 11:18:28AM -0400, David McBride wrote:
Okay, I figured this out on my own. This isn't as elegant but it definitely works:
By the way, your code can be simplified using forever; these ought to be equivalent:
fetchUDPSIP :: TChan a -> TChan B.ByteString -> IO () fetchUDPSIP commands chan = do sock <- getUDPSocket 5060 forever $ do result <- getUDP sock (atomically . writeTChan chan) result
fetchLine = forever $ do result <- Prelude.getLine Prelude.putStrLn result
-Brent
Have you looked at the Real World Haskell example [1] for reading from a UDP socket? In the inner "procMessages" the authors seem to show how to read one packet at a time without using unsafePerformIO. -deech [1] http://book.realworldhaskell.org/read/sockets-and-syslog.html in the section marked "UDP Syslog Server" On Mon, Jul 19, 2010 at 9:07 AM, David McBride <dmcbride@neondsl.com> wrote:
I am writing a voip server to take advantage of haskells awesome threading and parsing ability. At first everything was going great, but my thread that fetches udp makes use of unsafePerformIO:
fetchUDPSIP :: TChan B.ByteString -> IO () fetchUDPSIP chan = do sock <- getUDPSocket 5060 let results = (unstrict . repeat . getUDP) sock mapM_ (atomically . writeTChan chan) results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
It fetches it from a socket, and then writes it to a TChan. This results in a stream of bytestrings that another thread can read from. If I don't use unsafePerformIO, then it tries to read all possible packets before returning anything, and so it never writes to the TChan at all. The problem with doing it this way is that unsafePerformIO apparently stops every other thread from doing anything while it is waiting for a packet.
But I can't think of a way to rewrite this function to do what I want. I'm kind of new to this, does anyone have any hints that could help me out?
Here's a simple version without any of the implementation details:
fetchLine = do let results = (unstrict . repeat) getLine mapM_ putStrLn results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
Yeah I ended up doing pretty much what they do. The problem was I thought I could collect all the IO actions one by one into an array and then just map some other IO action over the array, but apparently the IO monad doesn't like being lazy. What you end up having to do is do one IO action at a time, getting the udp, then sending it over the tchan immediately before attempting to fetch the next udp packet. I ended up with: fetchUDPSIP :: TChan a -> TChan B.ByteString -> IO () fetchUDPSIP commands chan = do sock <- getUDPSocket 5060 forever $ getUDP sock >>= atomically . writeTChan chan Which is perfectly fine. Thanks. On Mon, Jul 19, 2010 at 1:50 PM, aditya siram <aditya.siram@gmail.com>wrote:
Have you looked at the Real World Haskell example [1] for reading from a UDP socket? In the inner "procMessages" the authors seem to show how to read one packet at a time without using unsafePerformIO.
-deech
[1] http://book.realworldhaskell.org/read/sockets-and-syslog.html in the section marked "UDP Syslog Server"
On Mon, Jul 19, 2010 at 9:07 AM, David McBride <dmcbride@neondsl.com> wrote:
I am writing a voip server to take advantage of haskells awesome threading and parsing ability. At first everything was going great, but my thread that fetches udp makes use of unsafePerformIO:
fetchUDPSIP :: TChan B.ByteString -> IO () fetchUDPSIP chan = do sock <- getUDPSocket 5060 let results = (unstrict . repeat . getUDP) sock mapM_ (atomically . writeTChan chan) results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
It fetches it from a socket, and then writes it to a TChan. This results in a stream of bytestrings that another thread can read from. If I don't use unsafePerformIO, then it tries to read all possible packets before returning anything, and so it never writes to the TChan at all. The problem with doing it this way is that unsafePerformIO apparently stops every other thread from doing anything while it is waiting for a packet.
But I can't think of a way to rewrite this function to do what I want. I'm kind of new to this, does anyone have any hints that could help me out?
Here's a simple version without any of the implementation details:
fetchLine = do let results = (unstrict . repeat) getLine mapM_ putStrLn results where unstrict [] = [] unstrict (x:xs) = unsafePerformIO x:unstrict xs
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
participants (5)
-
aditya siram -
Benjamin Edwards -
Brent Yorgey -
David McBride -
Stephen Tetley