public EBCOperation(string name, object eventBasedComponent, IDispatcher dispatcher, AsynchronizerCache asyncerCache) : base(name) { _eventBasedComponent = eventBasedComponent; _dispatcher = dispatcher; _asyncerCache = asyncerCache; _inputPorts = OperationsFactory.Find_input_ports(_eventBasedComponent); var outputPorts = OperationsFactory.Find_output_ports(_eventBasedComponent); Assign_handlers_to_output_port_events(_eventBasedComponent, outputPorts, _ => { Action <IMessage> continueWith; Stack <Action <IMessage> > continuationStack; if (_tls.TryGetValue(Thread.CurrentThread, out continuationStack) && continuationStack.Count > 0) { continueWith = continuationStack.Peek(); } else { continueWith = _active_continueWith; } continueWith(_); }); }
public static IOperation Schedule_operation_according_to_attributes(AsynchronizerCache asyncerCache, MethodInfo operationMethod, IOperation operation) { var asyncAttr = operationMethod.GetCustomAttributes(true) .FirstOrDefault(attr => attr.GetType() == typeof(AsyncMethodAttribute)) as AsyncMethodAttribute; if (asyncAttr != null) { var asyncer = asyncerCache.Get(asyncAttr.ThreadPoolName, () => new AsynchronizeFIFO()); return(new AsyncWrapperOperation(asyncer, operation)); } var parallelAttr = operationMethod.GetCustomAttributes(true) .FirstOrDefault(attr => attr.GetType() == typeof(ParallelMethod)) as ParallelMethod; if (parallelAttr != null) { var parallelizer = asyncerCache.Get(parallelAttr.ThreadPoolName, () => new Parallelize()); return(new AsyncWrapperOperation(parallelizer, operation)); } return(operation); }
public void Async_EBC_method_throwing_exception() { var cache = new AsynchronizerCache(); var sut = new EBCOperation("math", new MyAsyncEbc(), null, cache); var are = new AutoResetEvent(false); FlowRuntimeException result = null; var input = new Message("math.ThrowException", 41); var methodOp = sut.Create_method_operation(input); methodOp.Implementation(input, _ => { }, ex => { result = ex; are.Set(); }); Assert.IsTrue(are.WaitOne(1000)); Assert.IsInstanceOf <ApplicationException>(result.InnerException); }
public void Wrap_parallel_EBC_method() { var cache = new AsynchronizerCache(); var sut = new EBCOperation("math", new MyParallelEbc(), null, cache); var are = new AutoResetEvent(false); IMessage result = null; Thread methodThread = null; var input = new Message("math.Inc", 41); var methodOp = sut.Create_method_operation(input); Assert.IsInstanceOf <AsyncWrapperOperation>(methodOp); methodOp.Implementation(input, _ => { result = _; methodThread = Thread.CurrentThread; are.Set(); }, _ => { }); Assert.IsTrue(are.WaitOne(1000)); Assert.AreEqual(42, (int)result.Data); Assert.AreNotSame(methodThread, Thread.CurrentThread); }
public void Stress_test_parallel_method() { var cache = new AsynchronizerCache(); var sut = new EBCOperation("math", new MyParallelEbc(), null, cache); var are = new AutoResetEvent(false); var results = new List <int>(); var threads = new Dictionary <long, int>(); var exceptions = new List <string>(); const int N = 2000; for (var i = 1; i <= N; i++) { var input = new Message("math.Inc", i); var methodOp = sut.Create_method_operation(input); Assert.IsInstanceOf <AsyncWrapperOperation>(methodOp); methodOp.Implementation(input, _ => { lock (results) { results.Add((int)_.Data); var thUsage = 0; if (threads.TryGetValue(Thread.CurrentThread.GetHashCode(), out thUsage)) { threads[Thread.CurrentThread.GetHashCode()] = thUsage + 1; } else { threads.Add(Thread.CurrentThread.GetHashCode(), 1); } if (results.Count == N) { are.Set(); } } }, ex => { lock (exceptions) { exceptions.Add(string.Format("data==[{0}] -> {1}", (int)input.Data, ex.ToString())); } }); } var waitOne = are.WaitOne(2000); Console.WriteLine("count: {0}, thread count: {1}, ex count: {2}", results.Count, threads.Count, exceptions.Count); foreach (var th in threads) { Console.WriteLine("{1} x thread #{0}", th.Key, th.Value); } Console.WriteLine("thread usage total: {0}", threads.Values.Sum()); for (var i = 0; i < Math.Min(5, exceptions.Count); i++) { Console.WriteLine("*** {0}: {1}", i, exceptions[i]); } Assert.IsTrue(waitOne); }
// Creating continuations again and again for every output message is very inefficient. // But right now it´s simple and serves the purpose. It can be optimized later on. public static IOperation Create_method_operation(object instance, MethodInfo operationMethod, AsynchronizerCache asyncerCache) { var name = operationMethod.Name; OperationAdapter implementation; if (Is_a_procedure(operationMethod)) { if (operationMethod.GetParameters().Length == 0) { implementation = (input, outputCont, _) => { operationMethod.Invoke(instance, null); outputCont(new Message(name, null, input.CorrelationId)); } } ; else if (Parameter_types_ok(operationMethod, "c")) { implementation = (input, outputCont, _) => operationMethod.Invoke(instance, new[] { Create_continuation(operationMethod.GetParameters()[0], name, input, outputCont) }); } else if (Parameter_types_ok(operationMethod, "v")) { implementation = (input, outputCont, _) => { operationMethod.Invoke(instance, new[] { input.Data }); outputCont(new Message(name, null, input.CorrelationId)); } } ; else if (Parameter_types_ok(operationMethod, "cc")) { implementation = (input, outputCont, _) => operationMethod.Invoke(instance, new[] { Create_continuation(operationMethod.GetParameters()[0], name + Get_continuation_output_portname(operationMethod.GetParameters()[0]), input, outputCont), Create_continuation(operationMethod.GetParameters()[1], name + Get_continuation_output_portname(operationMethod.GetParameters()[1]), input, outputCont) }); } else if (Parameter_types_ok(operationMethod, "vc")) { implementation = (input, outputCont, _) => operationMethod.Invoke(instance, new[] { input.Data, Create_continuation(operationMethod.GetParameters()[1], name, input, outputCont) }); } else if (Parameter_types_ok(operationMethod, "vcc")) { implementation = (input, outputCont, _) => operationMethod.Invoke(instance, new[] { input.Data, Create_continuation(operationMethod.GetParameters()[1], name + Get_continuation_output_portname(operationMethod.GetParameters()[1]), input, outputCont), Create_continuation(operationMethod.GetParameters()[2], name + Get_continuation_output_portname(operationMethod.GetParameters()[2]), input, outputCont) }); } else { throw new NotImplementedException(string.Format("{0}.{1}: Procedure signature not supported as an operation!", instance.GetType().Name, operationMethod.Name)); } } else if (operationMethod.GetParameters().Length == 0) { implementation = (input, outputCont, _) => { var result = operationMethod.Invoke(instance, null); outputCont(new Message(name, result, input.CorrelationId)); } } ; else if (Parameter_types_ok(operationMethod, "v")) { implementation = (input, outputCont, _) => { var result = operationMethod.Invoke(instance, new[] { input.Data }); outputCont(new Message(name, result, input.CorrelationId)); } } ; else { throw new NotImplementedException(string.Format("{0}.{1}: Function signature not supported as an operation!", instance.GetType().Name, operationMethod.Name)); } OperationAdapter exceptionAwareImplementation = (input, outputCont, _) => { try { implementation(input, outputCont, _); } catch (TargetInvocationException ex) { throw ex.InnerException; } catch (Exception ex) { throw ex; } }; return(Schedule_operation_according_to_attributes(asyncerCache, operationMethod, new Operation(name, exceptionAwareImplementation))); }