/// <summary> /// Creates an asynchronous computation that executes all the given asynchronous computations, initially queueing each as work items and using a fork/join pattern. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="ms"></param> /// <returns></returns> public static Async <ImmutableList <T> > Parallel <T>(this ImmutableList <Async <T> > ms) { var empty = new ImmutableList <T>(); return(() => { var num = (uint)Math.Min(8, ms.Count); // 64 is maximum here if (num == 0) { return empty; } var xs = ms.Take(num); var rest = ms.RemoveRange(0, (int)num); var asyncs = xs.Map(x => { var handle = new AsyncEventHandle <T>(); x.Bind <T, Unit>(v => () => handle.Complete(v)).Start(); return handle; }); WaitHandle.WaitAll(asyncs.Map(ah => (WaitHandle)ah.DoneEvent).ToArray()); var ps = asyncs.Map(x => x.Result()); return empty.AddRange(rest.Count > 0 ? ps.AddRange(rest.Parallel().RunSynchronously()) : ps); }); }
/// <summary> /// Posts a message to an agent and await a reply on the channel, synchronously. /// </summary> /// <param name="f">The lambda providing the message.</param> /// <returns>The agents reply</returns> public TReply PostAndReply(Func <AsyncReplyChannel <TReply>, TMessage> f) { var handle = new AsyncEventHandle <TReply>(); Post(f(new AsyncReplyChannel <TReply>(handle.Complete))); handle.DoneEvent.WaitOne(); return(handle.Result()); }
/// <summary> /// Starts a child computation. This allows multiple asynchronous computations to be executed simultaneously. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="m"></param> /// <returns>A new computation that waits for the input computation to finish.</returns> public static Async <Async <T> > StartChild <T>(this Async <T> m) { return(() => { var handle = new AsyncEventHandle <T>(); m.StartAndReply(ch => new AsyncReplyChannel <T>(r => { ch.Reply(r); handle.Complete(r); return Unit.Default; })); return () => { handle.DoneEvent.WaitOne(); return handle.Result(); }; }); }
/// <summary> /// Creates an asynchronous computation that executes all the given asynchronous computations, initially queueing each as work items and using a fork/join pattern. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="ms"></param> /// <returns></returns> public static Async <IEnumerable <T> > Parallel <T>(this IEnumerable <Async <T> > ls) { return(() => { var ms = System.Collections.Immutable.ImmutableList.ToImmutableList(ls); var num = Math.Min(8, ms.Count); // 64 is maximum here if (num == 0) { return System.Collections.Immutable.ImmutableList <T> .Empty; } var xs = ms.GetRange(0, num); var rest = ms.RemoveRange(0, num); var asyncs = xs.Select(x => { var handle = new AsyncEventHandle <T>(); x.Bind <T, Unit>(v => () => handle.Complete(v)).Start(); return handle; }).ToImmutableList(); WaitHandle.WaitAll(asyncs.Select(ah => (WaitHandle)ah.DoneEvent).ToArray()); var ps = asyncs.Select(x => x.Result()); return System.Collections.Immutable.ImmutableList <T> .Empty.AddRange(ps).AddRange(rest.Parallel().RunSynchronously()); }); }