h$D@=      !"#$%&'()*+,-./0123456789:;< (c) Alexey Kuleshevich 2018-2019BSD3%Alexey Kuleshevich  experimental non-portableNoneh scheduler1Computation strategy to use when scheduling work. schedulerSequential computation schedulerSchedule workers to run on specific capabilities. Specifying an empty list  [] or using : will result in utilization of all available capabilities. schedulerSpecify 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  [] schedulerFigure out how many workers will this computation strategy create.Note - If at any point during program execution global number of capabilities gets changed with , 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  experimental non-portableNone% Z scheduler"A unique id for the worker in the + context. It will always be a number from 0 up to, but not including, the number of workers a scheduler has, which in turn can always be determined with  function.= schedulerA blocking unbounded queue that keeps the jobs in FIFO order and the results IORefs in reversed> scheduler;Pushes an item onto a queue and returns the previous count.? schedulerPops an item from the queue. The job returns the total job counts that is still left in the queue@ schedulerClears any jobs that haven't been started yet. Returns the number of jobs that are still in progress and have not been yet been completed.A schedulerExtracts all results available up to now, the uncomputed ones are discarded. This also has an affect of resetting the total job count to zero.BCDEFG =HIJKLMN>?OP@A  (c) Alexey Kuleshevich 2018-2020BSD3%Alexey Kuleshevich  experimental non-portableUnsafe  schedulerException that gets thrown whenever concurrent access is attempted to the Q schedulerWhen a co-worker dies of some exception, all the other ones will be terminated asynchronously with this one.R schedulerThis exception should normally be never seen in the wild and is for internal use only.S schedulerOne of workers experienced an exception, main thread will receive the same T.  schedulerA thread safe wrapper around , which allows it to be reused indefinitely and globally if need be. There is one already created in this library:   schedulerBatch is an artifical checkpoint that can be controlled by the user throughout the lifetime of a scheduler.U scheduler/This identifier is needed for tracking batches. 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 , 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.V schedulerReturns an opaque identifier for current batch of jobs, which can be used to either cancel the batch early or simply check if the batch has finished or not.W schedulerStops current batch and cancells all the outstanding jobs and the ones that are currently in progress.X scheduler5This is a result for premature ending of computation.Y schedulerThis value along with all results computed up to the moment when computation was cancelled or termianted will be returnedZ schedulerOnly this value will be returned all other results will get discarded scheduler#Computed results of scheduled jobs. scheduler3Finished normally with all scheduled jobs completed schedulerFinished early by the means of  or . schedulerFinished early by the means of  or .; [QRS\]^_`ab cdef ghijUklmnopqrstuvwxyVWzXYZ{|}~ (c) Alexey Kuleshevich 2018-2020BSD3%Alexey Kuleshevich  experimental non-portableNone #$% scheduler,Initialize a separate state for each worker. schedulerThe most basic scheduler that simply runs the task instead of scheduling it. Early termination requests are bluntly ignored. scheduler8This trivial scheduler will behave in a similar way as  with 3 computation strategy, except it is restricted to  , instead of  and the work isn't scheduled, but rather computed immediately. schedulerSame as , but works in 0 and returns results in an original LIFO order. schedulerThis is generally a faster way to traverse while ignoring the result rather than using . scheduler?Ignores the result of computation, thus avoiding some overhead. schedulerConversion to a list. Elements are expected to be in the orignal LIFO order, so calling : is still necessary for getting the results in FIFO order. schedulerComputation strategy schedulerHow to schedule work schedulerHow to collect results scheduler,Action that will be scheduling all the work. (c) Alexey Kuleshevich 2018-2021BSD3%Alexey Kuleshevich  experimental non-portableNone%?=! schedulerGet the underlying , which cannot access . 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)let scheduleGen scheduler = scheduleWorkState scheduler (MWC.uniform >=> \r -> yield >> threadDelay 200000 >> pure r)sort <$> withSchedulerWS states (M.replicateM 4 . scheduleGen) :: IO [Double][0.21734983682025255,0.5000843862105709,0.5759825622603018,0.8587171114177893]sort <$> withSchedulerWS states (M.replicateM 4 . scheduleGen) :: IO [Double][2.3598617298033475e-2,9.949679290089553e-2,0.38223134248645885,0.7408640677124702]In the above example we use four different random number generators from  +https://www.stackage.org/package/mwc-random `mwc-random` in order to generate 4 numbers, all in separate threads. The subsequent call to the  function with the same states 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. schedulerRun a scheduler with stateful workers, while discarding computation results. schedulerSame as ', except instead of a list it produces , which allows for distinguishing between the ways computation was terminated. schedulerSchedule 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. This is useful for identification of a thread that will be doing the work, since there is one-to-one mapping from  to  for a particular scheduler." 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  type is returned 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  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.$ schedulerSchedule 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.( schedulerSame as '6, but it does not retain the results of scheduled jobs) 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.* scheduler6This trivial scheduler will behave in the same way as / with 3 computation strategy, except it is restricted to  , instead of .+ scheduler'Map an action over each element of the  t2 acccording to the supplied computation strategy., scheduler Just like +, but restricted to * and discards the results of computation.- schedulerReplicate an action n times and schedule them acccording to the supplied computation strategy.. scheduler Just like -*, but discards the results of computation./ schedulerInitialize 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.It 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 can block, because it might lead to a potential 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 Important: 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.0 schedulerSame as /', except instead of a list it produces , which allows for distinguishing between the ways computation was terminated.1 schedulerSame as /), but discards results of submitted jobs.2 scheduler1Check if the supplied batch has already finished.3 schedulerCancel batch with supplied identifier, which will lead to scheduler to return  result. This is an idempotent operation and has no affect if currently running batch does not match supplied identifier. Returns  when cancelling did not succeed due to mismatched identifier or does not return at all since all jobs get cancelled immediately. For trivial schedulers however there is no way to perform concurrent cancelation and it will return .4 schedulerSame as 3>, but only works with schedulers that don't care about results5 schedulerSame as 4/, but the result of computation will be set to 6 schedulerThis function gives a way to get access to the main batch that started implicitely.7 schedulerRun a single batch of jobs. Supplied action will not return until all jobs placed on the queue are done or the whole batch is cancelled with one of these 3, 4 or 5.It waits for all scheduled jobs to finish and collects the computed results into a list. It is a blocking operation, but if there are no jobs in progress it will return immediately. It is safe to continue using the supplied scheduler after this function returns. However, if any of the jobs resulted in an exception it will be rethrown by this function, which, unless caught, will further put the scheduler in a terminated state.It is important to note that any job that hasn't had its results collected from the scheduler prior to starting the batch it will end up on the batch result list.8 schedulerSame as 7*, except it ignores results of computation9 schedulerSame as 7, except it produces  instead of a list./ schedulerComputation strategy scheduler,Action that will be scheduling all the work.0 schedulerComputation strategy scheduler,Action that will be scheduling all the work.1 schedulerComputation strategy scheduler,Action that will be scheduling all the work.9  !"#$%&'()*+,-./0123456789;/10*$%!&'( 78934526")#  -.+, (c) Alexey Kuleshevich 2020BSD3%Alexey Kuleshevich  experimental non-portableNone#$@: schedulerGlobal scheduler with 6 computation strategy that can be used anytime using <; scheduler4Create a new global scheduler, in case a single one : is not sufficient. It is important to note that too much parallelization can significantly degrate performance, therefore it is best not to use more than one scheduler at a time.< schedulerUse the global scheduler if it is not busy, otherwise initialize a temporary one. It means that this function by itself will not block, but if the same global scheduler used concurrently other schedulers might get created. :;< :;<  ! " " # $ % &  ' ( ) * +,-./ 0123456789:;<=>?@ABC DEFGHIJKKLMNOFPQRSTUVW X Y YZ[\ ] ^ _ ` ` a X b b c c d e f # g h i $ j k l ] m % n o p & q r  s t u v w x y y z { | } ~ZZZZ&scheduler-2.0.0-Bg0jfcFDcCoG9SwbFKjxRAControl.SchedulerControl.Scheduler.GlobalControl.Scheduler.ComputationControl.ConcurrentsetNumCapabilitiesControl.Scheduler.Queue Scheduler numWorkersControl.Scheduler.TypesglobalSchedulerwithSchedulerSinitWorkerStateswithSchedulerWSwithSchedulerWS_ withSchedulerwithScheduler_ cancelBatch terminatecancelBatchWith terminateWithControl.Scheduler.InternalwithSchedulerRwithTrivialSchedulerThreadIdCompSeqParOnParNPar'PargetCompWorkersWorkerId getWorkerIdMutexExceptionGlobalSchedulerBatch WorkerStates SchedulerWSResultsFinished FinishedEarlyFinishedEarlyWithtrivialScheduler_withTrivialSchedulerR traverse_unwrapSchedulerWSworkerStatesCompwithSchedulerWSRscheduleWorkStatescheduleWorkState_scheduleWorkId scheduleWork scheduleWork_scheduleWorkId_ replicateWorkreplicateWork_ terminate_traverseConcurrentlytraverseConcurrently_replicateConcurrentlyreplicateConcurrently_hasBatchFinished cancelBatch_getCurrentBatchrunBatch runBatch_ runBatchRnewGlobalSchedulerwithGlobalScheduler_Queue pushJQueue popJQueueclearPendingJQueue readResultsJQueue jqQueueRefjqLockJobJob_qQueueqStackqResultsqBatonmkJob newJQueueunblockPopJQueueblockPopJQueueWorkerTerminateExceptionWorkerExceptionbaseGHC.Exception.Type SomeExceptionBatchId_currentBatchId _cancelBatchEarly EarlyWithCancelBatchExceptionTerminateEarlyExceptionSchedulerStatus SchedulerIdleSchedulerWorkerExceptionglobalSchedulerCompglobalSchedulerMVarglobalSchedulerThreadIdsRef batchCancelbatchCancelWithbatchHasFinished getBatchId_workerStatesComp_workerStatesArray_workerStatesMutex _workerStates _getScheduler _numWorkers_scheduleWorkId _terminate_waitForCurrentBatch _earlyResults _batchEarlyJobsjobsNumWorkers jobsQueuejobsQueueCountjobsSchedulerStatusunEarly'primitive-0.7.1.0-Jxsyd70oUttYiCXCa0HqVControl.Monad.Primitive PrimMonad,unliftio-core-0.2.0.1-9GVcmaajsglG88oErAZOTVControl.Monad.IO.Unlift MonadUnliftIOwithTrivialSchedulerRIO Data.FoldablemapM_ scheduleJobs_ resultsToListGHC.ListreversewithSchedulerInternalwithSchedulerWSInternal scheduleJobsscheduleJobsWith initScheduler spawnWorkersterminateWorkersreverseResultssafeBracketOnErrorData.Traversable TraversableFoldableghc-prim GHC.TypesFalseTrue