Help with async library and killing child processes

Hi, I am currently learning Haskell, and really enjoying it, thankyou to the community for this well considered language. I have started using the async library, and I can't quite figure out some of the documentation, and I wonder if someone could help. https://hackage.haskell.org/package/async-2.2.2/docs/Control-Concurrent-Asyn... Makes the comment that: "This is a useful variant of async https://hackage.haskell.org/package/async-2.2.2/docs/Control-Concurrent-Asyn... that ensures an Async is never left running unintentionally." However, I can't see how I would use this. To make the example more concrete, I have a function that looks like this: runNodeHwBridgeUdp :: NodeHwInterface -> NodeHwUdpConfig-> IO() runNodeHwBridgeUdp (NodeHwInterface l0up l0down) config = do putStrLn "Starting Node bridge" -- Launch all the subprocesses: t0 <- async $ (runMsgUpReader hwBridgeSharedData l0up) t1 <- async $ (evalStateT (runUDPWriter hwBridgeSharedData) (initialUdpDispatchData timeUs) ) t2 <- async $ (runUDPReader hwBridgeSharedData l0down) putStrLn "Created child processes. Waiting...." (a, is_exception) <- waitAnyCatchCancel [t0, t1, t2] case is_exception of Right _ -> do error "SHOULD NOT GET HERE" Left exception -> do case (fromException exception) of Just (ex :: HwDestroyException) -> do putStrLn $ "BRIDGE ENDING: >>>> GOOD: SHUTDOWN: " ++ show exception Nothing -> do throwIO exception return () This process launches 3 child processes, and then waits on them. I launch this function as an async-process, and it would be really helpful if when I "cancel"ed it, it would also also cancelled the children, but I don't understand how I would structure that... t0 <- withAsync $ (runMsgUpReader hwBridgeSharedData l0up) $ \async -> do ???? t1 <- withAsync $ (evalStateT (runUDPWriter hwBridgeSharedData) (initialUdpDispatchData timeUs) ) $ \async -> do ???? t2 <- async $ (runUDPReader hwBridgeSharedData l0down) $ \async -> do ???? I feel like I must be missing something here. I'd appreciate any input; many thanks for your time, Mike

Hi, I think you're looking for Concurrently:
https://hackage.haskell.org/package/async-2.2.2/docs/Control-Concurrent-Asyn...
On Wed, Mar 18, 2020 at 4:52 AM Michael Hull
Hi, I am currently learning Haskell, and really enjoying it, thankyou to the community for this well considered language. I have started using the async library, and I can't quite figure out some of the documentation, and I wonder if someone could help.
https://hackage.haskell.org/package/async-2.2.2/docs/Control-Concurrent-Asyn...
Makes the comment that: "This is a useful variant of async https://hackage.haskell.org/package/async-2.2.2/docs/Control-Concurrent-Asyn... that ensures an Async is never left running unintentionally." However, I can't see how I would use this.
To make the example more concrete, I have a function that looks like this:
runNodeHwBridgeUdp :: NodeHwInterface -> NodeHwUdpConfig-> IO() runNodeHwBridgeUdp (NodeHwInterface l0up l0down) config = do putStrLn "Starting Node bridge"
-- Launch all the subprocesses: t0 <- async $ (runMsgUpReader hwBridgeSharedData l0up) t1 <- async $ (evalStateT (runUDPWriter hwBridgeSharedData) (initialUdpDispatchData timeUs) ) t2 <- async $ (runUDPReader hwBridgeSharedData l0down)
putStrLn "Created child processes. Waiting...." (a, is_exception) <- waitAnyCatchCancel [t0, t1, t2]
case is_exception of Right _ -> do error "SHOULD NOT GET HERE" Left exception -> do case (fromException exception) of Just (ex :: HwDestroyException) -> do putStrLn $ "BRIDGE ENDING: >>>> GOOD: SHUTDOWN: " ++ show exception Nothing -> do throwIO exception return ()
This process launches 3 child processes, and then waits on them. I launch this function as an async-process, and it would be really helpful if when I "cancel"ed it, it would also also cancelled the children, but I don't understand how I would structure that...
t0 <- withAsync $ (runMsgUpReader hwBridgeSharedData l0up) $ \async -> do ???? t1 <- withAsync $ (evalStateT (runUDPWriter hwBridgeSharedData) (initialUdpDispatchData timeUs) ) $ \async -> do ???? t2 <- async $ (runUDPReader hwBridgeSharedData l0down) $ \async -> do ????
I feel like I must be missing something here. I'd appreciate any input; many thanks for your time,
Mike
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

I've you're new to async, also check out my recent rework of the docs that talk about this topic specifically: https://github.com/simonmar/async/pull/105/files (To be available in the next release of async.)

If not for tight loops or other CPU intensive tasks, you may be interested in Edh, which introduces Go's goroutine to GHC runtime. But Edh threads add much higher overhead on top of GHC threads, so there's a price to pay for simplicity of end programmer's job. It's briefly described at https://github.com/e-wrks/edh/tree/master/Tour#program--threading-model https://github.com/e-wrks/edh/tree/master/Tour#program--threading-model . This is very new and I'm right now actively working on it for PoC of an STM powered in-memory graph database implementation. Best regards, Compl
On 2020-03-18, at 11:15, Niklas Hambüchen
wrote: I've you're new to async, also check out my recent rework of the docs that talk about this topic specifically:
https://github.com/simonmar/async/pull/105/files
(To be available in the next release of async.) _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

What's wrong with forkIO? Greets, Branimir. On 3/18/20 9:37 AM, YueCompl via Haskell-Cafe wrote:
If not for tight loops or other CPU intensive tasks, you may be interested in Edh, which introduces Go's goroutine to GHC runtime. But Edh threads add much higher overhead on top of GHC threads, so there's a price to pay for simplicity of end programmer's job.
It's briefly described at https://github.com/e-wrks/edh/tree/master/Tour#program--threading-model . This is very new and I'm right now actively working on it for PoC of an STM powered in-memory graph database implementation.
Best regards, Compl
On 2020-03-18, at 11:15, Niklas Hambüchen
mailto:mail@nh2.me> wrote: I've you're new to async, also check out my recent rework of the docs that talk about this topic specifically:
https://github.com/simonmar/async/pull/105/files
(To be available in the next release of async.) _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Idiomatic resource leakage prevention in short. An app wants to be as responsive to its users as practically feasible, it would try multiple paths to load-balanced resources, and use the first response that come back, then cancel other paths. Cancellation can help reducing vain computation in such architectures, sometimes largely enough.
On 2020-03-18, at 16:58, Branimir Maksimovic
wrote: What's wrong with forkIO?
Greets, Branimir.
On 3/18/20 9:37 AM, YueCompl via Haskell-Cafe wrote:
If not for tight loops or other CPU intensive tasks, you may be interested in Edh, which introduces Go's goroutine to GHC runtime. But Edh threads add much higher overhead on top of GHC threads, so there's a price to pay for simplicity of end programmer's job.
It's briefly described at https://github.com/e-wrks/edh/tree/master/Tour#program--threading-model https://github.com/e-wrks/edh/tree/master/Tour#program--threading-model . This is very new and I'm right now actively working on it for PoC of an STM powered in-memory graph database implementation.
Best regards, Compl
On 2020-03-18, at 11:15, Niklas Hambüchen
mailto:mail@nh2.me> wrote: I've you're new to async, also check out my recent rework of the docs that talk about this topic specifically:
https://github.com/simonmar/async/pull/105/files https://github.com/simonmar/async/pull/105/files
(To be available in the next release of async.) _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

I'm pretty sure you can't cancel goroutine. Actually I have very bad experience with thread cancelation. Therefore flags passed via channels/mvars or shared flags are used to stop threads. Greets, Branimir. On 3/18/20 10:10 AM, YueCompl wrote:
Idiomatic resource leakage prevention in short.
An app wants to be as responsive to its users as practically feasible, it would try multiple paths to load-balanced resources, and use the first response that come back, then cancel other paths. Cancellation can help reducing vain computation in such architectures, sometimes largely enough.
On 2020-03-18, at 16:58, Branimir Maksimovic
mailto:branimir.maksimovic@gmail.com> wrote: What's wrong with forkIO?
Greets, Branimir.
On 3/18/20 9:37 AM, YueCompl via Haskell-Cafe wrote:
If not for tight loops or other CPU intensive tasks, you may be interested in Edh, which introduces Go's goroutine to GHC runtime. But Edh threads add much higher overhead on top of GHC threads, so there's a price to pay for simplicity of end programmer's job.
It's briefly described at https://github.com/e-wrks/edh/tree/master/Tour#program--threading-model . This is very new and I'm right now actively working on it for PoC of an STM powered in-memory graph database implementation.
Best regards, Compl
On 2020-03-18, at 11:15, Niklas Hambüchen
mailto:mail@nh2.me> wrote: I've you're new to async, also check out my recent rework of the docs that talk about this topic specifically:
https://github.com/simonmar/async/pull/105/files
(To be available in the next release of async.) _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

No, not to cancel a thread, but the business task on that thread's way ahead. That's what Go's Context is designed for. About Go context from: https://blog.golang.org/context https://blog.golang.org/context At Google, we require that Go programmers pass a Context parameter as the first argument to every function on the call path between incoming and outgoing requests. This allows Go code developed by many different teams to interoperate well. It provides simple control over timeouts and cancelation and ensures that critical values like security credentials transit Go programs properly. Server frameworks that want to build on Context should provide implementations of Context to bridge between their packages and those that expect a Context parameter. Their client libraries would then accept a Context from the calling code. By establishing a common interface for request-scoped data and cancelation, Context makes it easier for package developers to share code for creating scalable services. I (and seems Windows api too) strongly agree that cancelling a thread is problematic: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-proc... https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-proc... TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems: If the target thread owns a critical section, the critical section will not be released. If the target thread is allocating memory from the heap, the heap lock will not be released. If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent. If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.
On 2020-03-18, at 17:16, Branimir Maksimovic
wrote: I'm pretty sure you can't cancel goroutine. Actually I have
very bad experience with thread cancelation. Therefore flags
passed via channels/mvars or shared flags are used to stop
threads.
Greets, Branimir.
On 3/18/20 10:10 AM, YueCompl wrote:
Idiomatic resource leakage prevention in short.
An app wants to be as responsive to its users as practically feasible, it would try multiple paths to load-balanced resources, and use the first response that come back, then cancel other paths. Cancellation can help reducing vain computation in such architectures, sometimes largely enough.
On 2020-03-18, at 16:58, Branimir Maksimovic
mailto:branimir.maksimovic@gmail.com> wrote: What's wrong with forkIO?
Greets, Branimir.
On 3/18/20 9:37 AM, YueCompl via Haskell-Cafe wrote:
If not for tight loops or other CPU intensive tasks, you may be interested in Edh, which introduces Go's goroutine to GHC runtime. But Edh threads add much higher overhead on top of GHC threads, so there's a price to pay for simplicity of end programmer's job.
It's briefly described at https://github.com/e-wrks/edh/tree/master/Tour#program--threading-model https://github.com/e-wrks/edh/tree/master/Tour#program--threading-model . This is very new and I'm right now actively working on it for PoC of an STM powered in-memory graph database implementation.
Best regards, Compl
On 2020-03-18, at 11:15, Niklas Hambüchen
mailto:mail@nh2.me> wrote: I've you're new to async, also check out my recent rework of the docs that talk about this topic specifically:
https://github.com/simonmar/async/pull/105/files https://github.com/simonmar/async/pull/105/files
(To be available in the next release of async.) _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

That's just library, not built into language. You can do it with forkIO as I do it per specifics of application. Greets, Branimir. On 3/18/20 11:06 AM, YueCompl wrote:
No, not to cancel a thread, but the business task on that thread's way ahead. That's what Go's Context is designed for.
* About Go context from: https://blog.golang.org/context
At Google, we require that Go programmers pass a Context parameter as the first argument to every function on the call path between incoming and outgoing requests. This allows Go code developed by many different teams to interoperate well. It provides simple control over timeouts and cancelation and ensures that critical values like security credentials transit Go programs properly.
Server frameworks that want to build on Context should provide implementations of Context to bridge between their packages and those that expect a Context parameter. Their client libraries would then accept a Context from the calling code. By establishing a common interface for request-scoped data and cancelation, Context makes it easier for package developers to share code for creating scalable services.
I (and seems Windows api too) strongly agree that cancelling a thread is problematic:
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-proc...
TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:
* If the target thread owns a critical section, the critical section will not be released. * If the target thread is allocating memory from the heap, the heap lock will not be released. * If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent. * If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.
On 2020-03-18, at 17:16, Branimir Maksimovic
mailto:branimir.maksimovic@gmail.com> wrote: I'm pretty sure you can't cancel goroutine. Actually I have
very bad experience with thread cancelation. Therefore flags
passed via channels/mvars or shared flags are used to stop
threads.
Greets, Branimir.
On 3/18/20 10:10 AM, YueCompl wrote:
Idiomatic resource leakage prevention in short.
An app wants to be as responsive to its users as practically feasible, it would try multiple paths to load-balanced resources, and use the first response that come back, then cancel other paths. Cancellation can help reducing vain computation in such architectures, sometimes largely enough.
On 2020-03-18, at 16:58, Branimir Maksimovic
mailto:branimir.maksimovic@gmail.com> wrote: What's wrong with forkIO?
Greets, Branimir.
On 3/18/20 9:37 AM, YueCompl via Haskell-Cafe wrote:
If not for tight loops or other CPU intensive tasks, you may be interested in Edh, which introduces Go's goroutine to GHC runtime. But Edh threads add much higher overhead on top of GHC threads, so there's a price to pay for simplicity of end programmer's job.
It's briefly described at https://github.com/e-wrks/edh/tree/master/Tour#program--threading-model . This is very new and I'm right now actively working on it for PoC of an STM powered in-memory graph database implementation.
Best regards, Compl
On 2020-03-18, at 11:15, Niklas Hambüchen
mailto:mail@nh2.me> wrote: I've you're new to async, also check out my recent rework of the docs that talk about this topic specifically:
https://github.com/simonmar/async/pull/105/files
(To be available in the next release of async.) _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Um, event processing applications by procedural programmers (part data analyst personnels for some) is a thing in my org, so I'm baking an DSL doing it.
On 2020-03-18, at 18:18, Branimir Maksimovic
wrote: That's just library, not built into language. You can do it with forkIO as I do it per specifics
of application.
Greets, Branimir.
On 3/18/20 11:06 AM, YueCompl wrote:
No, not to cancel a thread, but the business task on that thread's way ahead. That's what Go's Context is designed for.
About Go context from: https://blog.golang.org/context https://blog.golang.org/context At Google, we require that Go programmers pass a Context parameter as the first argument to every function on the call path between incoming and outgoing requests. This allows Go code developed by many different teams to interoperate well. It provides simple control over timeouts and cancelation and ensures that critical values like security credentials transit Go programs properly.
Server frameworks that want to build on Context should provide implementations of Context to bridge between their packages and those that expect a Context parameter. Their client libraries would then accept a Context from the calling code. By establishing a common interface for request-scoped data and cancelation, Context makes it easier for package developers to share code for creating scalable services. I (and seems Windows api too) strongly agree that cancelling a thread is problematic:
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-proc... https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-proc... TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems: If the target thread owns a critical section, the critical section will not be released. If the target thread is allocating memory from the heap, the heap lock will not be released. If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent. If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.
On 2020-03-18, at 17:16, Branimir Maksimovic
mailto:branimir.maksimovic@gmail.com> wrote: I'm pretty sure you can't cancel goroutine. Actually I have
very bad experience with thread cancelation. Therefore flags
passed via channels/mvars or shared flags are used to stop
threads.
Greets, Branimir.
On 3/18/20 10:10 AM, YueCompl wrote:
Idiomatic resource leakage prevention in short.
An app wants to be as responsive to its users as practically feasible, it would try multiple paths to load-balanced resources, and use the first response that come back, then cancel other paths. Cancellation can help reducing vain computation in such architectures, sometimes largely enough.
On 2020-03-18, at 16:58, Branimir Maksimovic
mailto:branimir.maksimovic@gmail.com> wrote: What's wrong with forkIO?
Greets, Branimir.
On 3/18/20 9:37 AM, YueCompl via Haskell-Cafe wrote:
If not for tight loops or other CPU intensive tasks, you may be interested in Edh, which introduces Go's goroutine to GHC runtime. But Edh threads add much higher overhead on top of GHC threads, so there's a price to pay for simplicity of end programmer's job.
It's briefly described at https://github.com/e-wrks/edh/tree/master/Tour#program--threading-model https://github.com/e-wrks/edh/tree/master/Tour#program--threading-model . This is very new and I'm right now actively working on it for PoC of an STM powered in-memory graph database implementation.
Best regards, Compl
> On 2020-03-18, at 11:15, Niklas Hambüchen
mailto:mail@nh2.me> wrote: > > I've you're new to async, also check out my recent rework of the docs that talk about this topic specifically: > > https://github.com/simonmar/async/pull/105/files https://github.com/simonmar/async/pull/105/files > > (To be available in the next release of async.) > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Hi Niklas and Patrick,
Thankyou both for the comments -- this is what I am looking for.
I have a follow-on question, if I have code like
getPages :: IO()
getPages = do (page1, page2, page3)
<- runConcurrently $ (,,)
<$> Concurrently (getURL "url1")
<*> Concurrently (getURL "url2")
<*> Concurrently (getURL "url3")
main :: IO()
main = do
f <- async getPages
cancel f
Am I guaranteed the the getURL() calls will definitely have either
finished, or cancel? (I looked through the source (
https://hackage.haskell.org/package/async-2.2.2/docs/src/Control.Concurrent....),
and I think so, because runConcurrently is implemented in terms of race,
which is implemented using withAsync, but I'm not confident with
interpreting Haskell!)
Many thanks,
Mike
On Wed, 18 Mar 2020 at 03:15, Niklas Hambüchen
I've you're new to async, also check out my recent rework of the docs that talk about this topic specifically:
https://github.com/simonmar/async/pull/105/files
(To be available in the next release of async.)

I use my nonblocking library: eg for IRC bot: let myCallbacks = defaultCallbacks { done_connected = binded, done_reading = response_get tm ref stdgen gsref, done_writing = response_written, done_closed = \pl s -> do putStrLn "peer closed, reconnecting" s <- socket myCallbacks connect pl s "83.140.172.212:6667" return 1, handle_error = \pl s buf len-> do str <- peekCStringLen (buf,fromIntegral len) putStrLn $ "error "++str++", reconnecting" s <- socket myCallbacks connect pl s "83.140.172.212:6667" return 1, tick = binded_tick tm } s <- socket myCallbacks pl <- epoll 1000 connect pl s "83.140.172.212:6667" run_loop pl (-1) On 3/19/20 3:40 PM, Michael Hull wrote:
Hi Niklas and Patrick,
Thankyou both for the comments -- this is what I am looking for.
I have a follow-on question, if I have code like
getPages :: IO() getPages = do (page1, page2, page3) <- runConcurrently $ (,,) <$> Concurrently (getURL "url1") <*> Concurrently (getURL "url2") <*> Concurrently (getURL "url3")
main :: IO() main = do f <- async getPages cancel f
Am I guaranteed the the getURL() calls will definitely have either finished, or cancel? (I looked through the source (https://hackage.haskell.org/package/async-2.2.2/docs/src/Control.Concurrent....), and I think so, because runConcurrently is implemented in terms of race, which is implemented using withAsync, but I'm not confident with interpreting Haskell!)
Many thanks,
Mike
On Wed, 18 Mar 2020 at 03:15, Niklas Hambüchen
mailto:mail@nh2.me> wrote: I've you're new to async, also check out my recent rework of the docs that talk about this topic specifically:
https://github.com/simonmar/async/pull/105/files
(To be available in the next release of async.)
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Hey Mike,
f <- async getPages cancel f
you haven't read the PR I linked carefully enough yet :) It essentially says to never use the `async` function, as that is almost never what you want Full docs, with what you need to read highlighted: https://github.com/nh2/async/blob/1d96dc555b70a4c5aba07f15d0c7895545eb8582/C...
Am I guaranteed the the getURL() calls will definitely have either finished, or cancel?
For do (page1, page2, page3) <- runConcurrently $ (,,) <$> Concurrently (getURL "url1") <*> Concurrently (getURL "url2") <*> Concurrently (getURL "url3") you are guaranteed that when `runConcurrently` returns, all 3 downloads have finished successfully. Only the `instance Alternative Concurrently` (that is, when you use <|>) is implemented in terms of `race`. You are using <*>, as implemented in the `instance Applicative Concurrently`, which uses `concurrently`, which waits for both of two actions. Your code in
main = do f <- async getPages cancel f
does not make much sense: Here you're starting a thread that would go off do something, but then you immediately cancel that thread, so it won't achieve anything. You do not need to wrap things into additional `async`s. You can directly do, for example: main :: IO () main = do (page1, page2, page3) <- runConcurrently $ (,,) <$> Concurrently (getURL "url1") <*> Concurrently (getURL "url2") <*> Concurrently (getURL "url3") putStrLn "Here are the page contents:" putStrLn page1 putStrLn page2 putStrLn page3 Hope that helps! Niklas

Hey Niklas,
Thanks for your explanation -- it was useful to read.
Is there a way to get the result of "either of three calls to getUrl" as
opposed to "all three calls"?
'Cause that's what Mike seems to want.
--
Best regards,
Artem
On Thu, 19 Mar 2020 at 21:38, Niklas Hambüchen
Hey Mike,
f <- async getPages cancel f
you haven't read the PR I linked carefully enough yet :)
It essentially says to never use the `async` function, as that is almost never what you want
Full docs, with what you need to read highlighted:
https://github.com/nh2/async/blob/1d96dc555b70a4c5aba07f15d0c7895545eb8582/C...
Am I guaranteed the the getURL() calls will definitely have either finished, or cancel?
For
do (page1, page2, page3) <- runConcurrently $ (,,) <$> Concurrently (getURL "url1") <*> Concurrently (getURL "url2") <*> Concurrently (getURL "url3")
you are guaranteed that when `runConcurrently` returns, all 3 downloads have finished successfully.
Only the `instance Alternative Concurrently` (that is, when you use <|>) is implemented in terms of `race`.
You are using <*>, as implemented in the `instance Applicative Concurrently`, which uses `concurrently`, which waits for both of two actions.
Your code in
main = do f <- async getPages cancel f
does not make much sense: Here you're starting a thread that would go off do something, but then you immediately cancel that thread, so it won't achieve anything.
You do not need to wrap things into additional `async`s. You can directly do, for example:
main :: IO () main = do (page1, page2, page3) <- runConcurrently $ (,,) <$> Concurrently (getURL "url1") <*> Concurrently (getURL "url2") <*> Concurrently (getURL "url3") putStrLn "Here are the page contents:" putStrLn page1 putStrLn page2 putStrLn page3
Hope that helps!
Niklas _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Is there a way to get the result of "either of three calls to getUrl" as opposed to "all three calls"? 'Cause that's what Mike seems to want.
That's what the Alternative instance of Concurrently is for. The result of
`doA <|> doB` is the result of the argument that finished first. (<|>) =
race.
firstResult <- runConcurrently (Concurrently (getURL "url1") <|>
Concurrently (getURL "url2") <|> Concurrently (getURL "url3"))
or
firstResult <- runConcurrently $ asum $ map (Concurrently . getURL) [
"url1", "url2", "url3" ]
On Fri, Mar 20, 2020 at 9:44 AM Artem Pelenitsyn
Hey Niklas,
Thanks for your explanation -- it was useful to read.
Is there a way to get the result of "either of three calls to getUrl" as opposed to "all three calls"? 'Cause that's what Mike seems to want.
-- Best regards, Artem
On Thu, 19 Mar 2020 at 21:38, Niklas Hambüchen
wrote: Hey Mike,
f <- async getPages cancel f
you haven't read the PR I linked carefully enough yet :)
It essentially says to never use the `async` function, as that is almost never what you want
Full docs, with what you need to read highlighted:
https://github.com/nh2/async/blob/1d96dc555b70a4c5aba07f15d0c7895545eb8582/C...
Am I guaranteed the the getURL() calls will definitely have either finished, or cancel?
For
do (page1, page2, page3) <- runConcurrently $ (,,) <$> Concurrently (getURL "url1") <*> Concurrently (getURL "url2") <*> Concurrently (getURL "url3")
you are guaranteed that when `runConcurrently` returns, all 3 downloads have finished successfully.
Only the `instance Alternative Concurrently` (that is, when you use <|>) is implemented in terms of `race`.
You are using <*>, as implemented in the `instance Applicative Concurrently`, which uses `concurrently`, which waits for both of two actions.
Your code in
main = do f <- async getPages cancel f
does not make much sense: Here you're starting a thread that would go off do something, but then you immediately cancel that thread, so it won't achieve anything.
You do not need to wrap things into additional `async`s. You can directly do, for example:
main :: IO () main = do (page1, page2, page3) <- runConcurrently $ (,,) <$> Concurrently (getURL "url1") <*> Concurrently (getURL "url2") <*> Concurrently (getURL "url3") putStrLn "Here are the page contents:" putStrLn page1 putStrLn page2 putStrLn page3
Hope that helps!
Niklas _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

That makes sense. Thanks a lot, Patrick!
On Thu, Mar 19, 2020, 11:01 PM Patrick Chilton
Is there a way to get the result of "either of three calls to getUrl" as
opposed to "all three calls"? 'Cause that's what Mike seems to want.
That's what the Alternative instance of Concurrently is for. The result of `doA <|> doB` is the result of the argument that finished first. (<|>) = race.
firstResult <- runConcurrently (Concurrently (getURL "url1") <|> Concurrently (getURL "url2") <|> Concurrently (getURL "url3"))
or
firstResult <- runConcurrently $ asum $ map (Concurrently . getURL) [ "url1", "url2", "url3" ]
On Fri, Mar 20, 2020 at 9:44 AM Artem Pelenitsyn
wrote: Hey Niklas,
Thanks for your explanation -- it was useful to read.
Is there a way to get the result of "either of three calls to getUrl" as opposed to "all three calls"? 'Cause that's what Mike seems to want.
-- Best regards, Artem
On Thu, 19 Mar 2020 at 21:38, Niklas Hambüchen
wrote: Hey Mike,
f <- async getPages cancel f
you haven't read the PR I linked carefully enough yet :)
It essentially says to never use the `async` function, as that is almost never what you want
Full docs, with what you need to read highlighted:
https://github.com/nh2/async/blob/1d96dc555b70a4c5aba07f15d0c7895545eb8582/C...
Am I guaranteed the the getURL() calls will definitely have either finished, or cancel?
For
do (page1, page2, page3) <- runConcurrently $ (,,) <$> Concurrently (getURL "url1") <*> Concurrently (getURL "url2") <*> Concurrently (getURL "url3")
you are guaranteed that when `runConcurrently` returns, all 3 downloads have finished successfully.
Only the `instance Alternative Concurrently` (that is, when you use <|>) is implemented in terms of `race`.
You are using <*>, as implemented in the `instance Applicative Concurrently`, which uses `concurrently`, which waits for both of two actions.
Your code in
main = do f <- async getPages cancel f
does not make much sense: Here you're starting a thread that would go off do something, but then you immediately cancel that thread, so it won't achieve anything.
You do not need to wrap things into additional `async`s. You can directly do, for example:
main :: IO () main = do (page1, page2, page3) <- runConcurrently $ (,,) <$> Concurrently (getURL "url1") <*> Concurrently (getURL "url2") <*> Concurrently (getURL "url3") putStrLn "Here are the page contents:" putStrLn page1 putStrLn page2 putStrLn page3
Hope that helps!
Niklas _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
participants (6)
-
Artem Pelenitsyn
-
Branimir Maksimovic
-
Michael Hull
-
Niklas Hambüchen
-
Patrick Chilton
-
YueCompl