Closed DKurilo closed 4 years ago
Hey this is an interesting use of a bounded queue! We've done some revision to make this more concise:
tictoc
and the TQueue String
so we can just focus on a single queue; I do think a queue of log messages is a good example and it's something we use in everyday code, but I'd like to give logging its own dedicated page.forConcurrently_
from the async
package so that we don't have to deal with waiting for the threads to finish.bracket_
to acquire and release the TBQueue ()
lock so that we don't have to think so hard about the exception handling.{-# LANGUAGE NumericUnderscores #-}
module Main where
import Control.Concurrent
import Control.Concurrent.Async
import Control.Concurrent.STM
import Control.Exception.Safe
import System.IO
import System.Random
-- Let's pretend we will make making many requests to some vendor's API,
-- and the vendor may block us if we make too many simultaneous requests.
vendorApiCall :: Int -> IO Int
vendorApiCall n =
do
t <- getStdRandom (randomR (500_000, 1_500_000))
threadDelay t
return (n * n)
main :: IO ()
main =
do
hSetBuffering stdout LineBuffering
-- This bounded queue can contain only five elements. Each request will
-- begin by adding an element onto the queue and end by removing an
-- element from the queue, thus ensuring that no more than five tasks
-- can ever be running at once.
bq <- atomically (newTBQueue 5)
let
acquire = atomically (writeTBQueue bq ())
release = atomically (readTBQueue bq)
-- `forConcurrently_` is just like `for_`, but concurrent.
forConcurrently_ [1 .. 10] $ \x ->
bracket_ acquire release $
do
putStrLn ("start: " ++ show x)
result <- vendorApiCall x
putStrLn ("finish: " ++ show x ++ ", result: " ++ show result)
What do you think, is it still clear enough?
This'll be released under the creative commons CC BY-NC 4.0 license - Please let us know if that's okay and how you'd like to be attributed.
@chris-martin , you almost completely change my example, so surely I'm okay with suggested license. :) Currently, working with experienced Haskell developers a lot better for me than any attribution. And thank you for your comment! Personally, I prefer to have as little amount of "magic" (like bracket and forConcurrently) in examples as it's possible. I'm still learning Haskell and I know, "magic" makes examples obscure and it's difficult to understand what exactly happens under the hood. Not sure if a lot of people will check forConcurrently or bracket implementation. But I also know how difficult to find proper using and "best practices" in Haskell. So I really like your changes. Do you want me to update the code? P.S. It would be great to add link to documentation (or at least to hoogle) for each library function in code, so it will be easier to find implementation for forConcurrently_. :) Maybe it will make beginners read it.
We can update the code after we merge, either way's fine. Sure we shuffled a lot around but having the starting point to work with is huge :) Is "Dima Kurilo" the name we should attach to it? (we can link to a blog or twitter account or something too if you'd like)
I perpetually struggle with how much "magic" to include, trying to find the right balance between fundamentals and my presumed readers' impatience. Getting familiar with a set of primitives is a real source of comfort, but if we eschew conveniences that are commonplace in other languages, then that can lead authors down a road that makes Haskell seem way harder than other languages in places where it doesn't need to be. The Phrasebook in particular is an intentional departure from our usual impulses and we're trying to err on the side of giving readers quick easy answers, as long as the things we're recommending are still very generally useful (and I believe forConcurrently_
and bracket_
are).
In this case I think it also really comes down to trying to present one small topic at a time; worrying about how to fork and join threads was distracting while what we were trying to think about was queues. The topics 1. forking/joining and the concept of blocking threads; and 2. exception handling; would make great separate pages with more room to show how to do more things from primitives.
Great! Thank you. Yes, you can use "Dima Kurilo" and my twitter: https://twitter.com/DimaKurilo . Got it. As someone who uses haskell phrasebook, I like it. Thank you.
Fixes #14 I hope it's good enough. In case I did it not clear enough, write me, please.