!j0/      !"#$%&'()*+,-. (c) Alexey Kuleshevich 2018-2019BSD3%Alexey Kuleshevich <lehins@yandex.ru> experimental non-portableNoneX_go scheduler1Computation strategy to use when scheduling work. schedulerSequential computation schedulerKSchedule workers to run on specific capabilities. Specifying an empty list  [] or using : will result in utilization of all available capabilities. schedulerRSpecify the number of workers that will be handling all the jobs. Difference from 0 is that workers can jump between cores. Using  02 will result in using all available capabilities. scheduler8Parallel computation using all available cores. Same as  0 scheduler8Parallel computation using all available cores. Same as  [] schedulerBFigure out how many workers will this computation strategy create.Note] - If at any point during program execution global number of capabilities gets changed with R, it will have no affect on this function, unless it hasn't yet been called with  or  arguments. (c) Alexey Kuleshevich 2018-2019BSD3%Alexey Kuleshevich <lehins@yandex.ru> experimental non-portableNone$M scheduler"A unique id for the worker in the + context. It will always be a number from 0o up to, but not including, the number of workers a scheduler has, which in turn can always be determined with  function./ scheduler`A blocking unbounded queue that keeps the jobs in FIFO order and the results IORefs in reversed 0123 45678 (c) Alexey Kuleshevich 2018-2019BSD3%Alexey Kuleshevich <lehins@yandex.ru> experimental non-portableUnsafe_-j  schedulerJException that gets thrown whenever concurrent access is attempted to the  9 schedulermWhen a co-worker dies of some exception, all the other ones will be terminated asynchronously with this one.: schedulerVThis exception should normally be never seen in the wild and is for internal use only.; schedulerKOne of workers experienced an exception, main thread will receive the same <.  schedulerEach worker is capable of keeping it's own state, that can be share for different schedulers, but not at the same time. In other words using the same   on  @ concurrently will result in an error. Can be initialized with   schedulerThis is a wrapper around F, but it also keeps a separate state for each individual worker. See   or  . for ways to construct and use this data type. scheduler#Main type for scheduling work. See   or . for ways to construct and use this data type. scheduler%Computated outcome of scheduled jobs. scheduler3Finished normally with all scheduled jobs completed schedulerFinished early by the means of . schedulerFinished early by the means of ." =9:;>?@A BCDE FGHIJKLMNOPQR (c) Alexey Kuleshevich 2018-2019BSD3%Alexey Kuleshevich <lehins@yandex.ru> experimental non-portableNone "#$SX_g! schedulerGet the underlying , which cannot access  . scheduler,Initialize a separate state for each worker. scheduler?Get the computation strategy the states where initialized with. scheduler.Run a scheduler with stateful workers. Throws  5 if an attempt is made to concurrently use the same   with another  .ExamplesA good example of using stateful workers would be generation of random number in parallel. A lof of times random number generators are not gonna be thread safe, so we can work around this problem, by using a separate stateful generator for each of the workers. -import Control.Monad as M ((>=>), replicateM).import Control.Concurrent (yield, threadDelay)import Data.List (sort)]-- ^ Above imports are used to make sure output is deterministic, which is needed for doctestimport System.Random.MWC as MWC+import Data.Vector.Unboxed as V (singleton)_states <- initWorkerStates (ParN 4) (MWC.initialize . V.singleton . fromIntegral . getWorkerId)ulet scheduleGen scheduler = scheduleWorkState scheduler (MWC.uniform >=> \r -> yield >> threadDelay 200000 >> pure r)Msort <$> withSchedulerWS states (M.replicateM 4 . scheduleGen) :: IO [Double]N[0.21734983682025255,0.5000843862105709,0.5759825622603018,0.8587171114177893]Msort <$> withSchedulerWS states (M.replicateM 4 . scheduleGen) :: IO [Double]S[2.3598617298033475e-2,9.949679290089553e-2,0.38223134248645885,0.7408640677124702]JIn the above example we use four different random number generators from  +https://www.stackage.org/package/mwc-random `mwc-random`V in order to generate 4 numbers, all in separate threads. The subsequent call to the  function with the same statesR is allowed to reuse the same generators, thus avoiding expensive initialization. Side note - The example presented was crafted with slight trickery in order to guarantee that the output is deterministic, so if you run instructions exactly the same way in GHCI you will get the exact same output. Non-determinism comes from thread scheduling, rather than from random number generator, because we use exactly the same seed for each worker, but workers run concurrently. Exact output is not really needed, except for the doctests to pass. schedulerLRun a scheduler with stateful workers, while discarding computation results. schedulerSame as ', except instead of a list it produces O, which allows for distinguishing between the ways computation was terminated. schedulerASchedule a job that will get a worker state passed as an argument schedulerSame as +, but dont' keep the result of computation. schedulerGet the number of workers. Will mainly depend on the computation strategy and/or number of capabilities you have. Related function is . schedulerSchedule an action to be picked up and computed by a worker from a pool of jobs. Argument supplied to the job will be the id of the worker doing the job. schedulerAs soon as possible try to terminate any computation that is being performed by all workers managed by this scheduler and collect whatever results have been computed, with supplied element guaranteed to being the last one. In case when G is the return type this function will cause the scheduler to produce  Important - With  strategy this will not stop other scheduled tasks from being computed, although it will make sure their results are discarded. schedulerSame as , but returning a single element list containing the supplied argument. This can be very useful for parallel search algorithms. In case when G is the return type this function will cause the scheduler to produce  Important - Same as with , when  strategy is used, this will not prevent computation from continuing, but the scheduler will return only the result supplied to this function. scheduler]Schedule an action to be picked up and computed by a worker from a pool of jobs. Similar to +, except the job doesn't get the worker id.  schedulerSame as , but only for a  that doesn't keep the results.! schedulerSame as , but only for a  that doesn't keep the results." scheduler Schedule the same action to run n( times concurrently. This differs from *# by allowing the caller to use the , freely, or to allow early termination via 8 across all (identical) threads. To be called within a , block.# scheduler Similar to  , but for a / that does not keep any results of computation. Important - In case of 2 computation strategy this function has no affect.$ scheduler}The most basic scheduler that simply runs the task instead of scheduling it. Early termination requests are bluntly ignored.% scheduler6This trivial scheduler will behave in the same way as , with 3 computation strategy, except it is restricted to S , instead of T.& scheduler7This trivial scheduler will behave in a similar way as - with 3 computation strategy, except it is restricted to S, instead of T? and the work isn't scheduled, but rather computed immediately.' schedulerWThis is generally a faster way to traverse while ignoring the result rather than using U.( scheduler'Map an action over each element of the V t2 acccording to the supplied computation strategy.) scheduler Just like (, but restricted to W* and discards the results of computation.* schedulerReplicate an action nJ times and schedule them acccording to the supplied computation strategy.+ scheduler Just like **, but discards the results of computation.X scheduler Similarly to C, but ignores the result of computation, thus having less overhead.Y scheduler,Helper function to place required number of Retire instructions on the job queue.Z schedulerKDecrease a counter by one and perform an action when it drops down to zero.[ scheduleryRuns the worker until the job queue is exhausted, at which point it will execute the final task of retirement and return, schedulerxInitialize a scheduler and submit jobs that will be computed sequentially or in parallelel, which is determined by the utation strategy.(Here are some cool properties about the ,:This function will block until all of the submitted jobs have finished or at least one of them resulted in an exception, which will be re-thrown at the callsite.VIt is totally fine for nested jobs to submit more jobs for the same or other schedulerIt is ok to initialize multiple schedulers at the same time, although that will likely result in suboptimal performance, unless workers are pinned to different capabilities.Warning: It is pretty dangerous to schedule jobs that do blocking \, since it can easily lead to deadlock, if you are not careful. Consider this example. First execution works fine, since there are two scheduled workers, and one can unblock the other, but the second scenario immediately results in a deadlock.}withScheduler (ParOn [1,2]) $ \s -> newEmptyMVar >>= (\ mv -> scheduleWork s (readMVar mv) >> scheduleWork s (putMVar mv ()))[(),()]import System.Timeouttimeout 1000000 $ withScheduler (ParOn [1]) $ \s -> newEmptyMVar >>= (\ mv -> scheduleWork s (readMVar mv) >> scheduleWork s (putMVar mv ()))Nothing ImportantR: In order to get work done truly in parallel, program needs to be compiled with  -threaded GHC flag and executed with  +RTS -N -RTS to use all available cores.- schedulerSame as ,', except instead of a list it produces O, which allows for distinguishing between the ways computation was terminated.. schedulerSame as ,), but discards results of submitted jobs.] scheduler5Specialized exception handler for the work scheduler.[ schedulerAction to run upon retirement, schedulerComputation strategy scheduler,Action that will be scheduling all the work.- schedulerComputation strategy scheduler,Action that will be scheduling all the work.. schedulerComputation strategy scheduler,Action that will be scheduling all the work.^ schedulerComputation strategy schedulerHow to schedule work schedulerHow to collect results schedulerAdjust results in some way scheduler,Action that will be scheduling all the work./  !"#$%&'()*+,-.1 ,.-$%& !"# *+()' _ ! "  #$%&'()*+,-./0123 456789:;<=>?@@ABC?DEFGHIJKLMNOPQQRSTUVWXYZA[\A]^A[_`abcdefghi&scheduler-1.4.2-1qponkubKz79ztAcNRC1bUControl.SchedulerControl.Scheduler.ComputationControl.ConcurrentsetNumCapabilitiesControl.Scheduler.Queue Scheduler numWorkersControl.Scheduler.InternalwithSchedulerSinitWorkerStateswithSchedulerWSwithSchedulerWS_ withSchedulerwithScheduler_ terminate terminateWithCompSeqParOnParNPar'PargetCompWorkersWorkerId getWorkerIdMutexException WorkerStates SchedulerWSResultsFinished FinishedEarlyFinishedEarlyWithunwrapSchedulerWSworkerStatesCompwithSchedulerWSRscheduleWorkStatescheduleWorkState_scheduleWorkId scheduleWork scheduleWork_scheduleWorkId_ replicateWork terminate_trivialScheduler_withTrivialSchedulerwithTrivialSchedulerR traverse_traverseConcurrentlytraverseConcurrently_replicateConcurrentlyreplicateConcurrently_withSchedulerRQueueJQueueJobRetireJob_mkJob newJQueue pushJQueue popJQueue readResultsWorkerTerminateExceptionWorkerExceptionbaseGHC.Exception.Type SomeExceptionSchedulerOutcomeSchedulerFinishedSchedulerTerminatedEarlySchedulerWorkerException_workerStatesComp_workerStatesArray_workerStatesMutex _workerStates _getScheduler _numWorkers_scheduleWorkId _terminate_terminateWithJobsjobsNumWorkers jobsQueue jobsCountRef(primitive-0.7.0.0-9xMM76CsovTEGnXCHiCdRJControl.Monad.Primitive PrimMonad,unliftio-core-0.1.2.0-6l4GP0ylCTM6crlVTDgRiKControl.Monad.IO.Unlift MonadUnliftIO Data.FoldablemapM_Data.Traversable TraversableFoldable scheduleJobs_retireWorkersNdropCounterOnZero runWorkerghc-prim GHC.TypesIOhandleWorkerExceptionwithSchedulerInternal