/// <summary> /// Matrix 연산 중에 현재 행보다 아래와 현재 열보다 오른쪽의 요소에 대해 작업을 Wavefront라 한다. 이를 병렬로 수행할 수 있도록 합니다. /// </summary> /// <param name="rows">매트릭스 행 수</param> /// <param name="cols">매트릭스 열 수</param> /// <param name="blocksPerRow">매트릭스 행 분할 수</param> /// <param name="blocksPerCol">매트릭스 열 분할 수</param> /// <param name="processBlock">매트릭스의 분할된 서브매트릭스를 처리할 델리게이트. processBlock(startRow, endRow, startCol, endCol);</param> public static void Wavefront(int rows, int cols, int blocksPerRow, int blocksPerCol, Action<int, int, int, int> processBlock) { rows.ShouldBePositive("rows"); cols.ShouldBePositive("cols"); processBlock.ShouldNotBeNull("processBlock"); blocksPerRow.ShouldBeInRange(1, rows + 1, "blocksPerRow"); blocksPerCol.ShouldBeInRange(1, cols + 1, "blocksPerCol"); if(IsDebugEnabled) log.Debug("매트릭스의 블록 분할에 따른 Wavefront 작업을 수행합니다. rows=[{0}], cols=[{1}], blocksPerRow=[{2}], blocksPerCol=[{3}]", rows, cols, blocksPerRow, blocksPerCol); int rowBlockSize = rows / blocksPerRow; int colBlockSize = cols / blocksPerCol; Wavefront(blocksPerRow, blocksPerCol, (r, c) => { int startRow = r * rowBlockSize; int endRow = (r < blocksPerRow - 1) ? startRow + rowBlockSize : rows; int startCol = c * colBlockSize; int endCol = (c < blocksPerCol - 1) ? startCol + colBlockSize : cols; if(IsDebugEnabled) log.Debug("매트릭스 서브 블럭 프로세싱... " + "r=[{0}], c=[{1}], rowBlockSize=[{2}], colBlockSize=[{3}], startRow=[{4}], endRow=[{5}], startCol=[{6}], endCol=[{7}]", r, c, rowBlockSize, colBlockSize, startRow, endRow, startCol, endCol); processBlock(startRow, endRow, startCol, endCol); }); if(IsDebugEnabled) log.Debug("매트릭스의 블록 분할에 따른 모든 Wavefront 작업을 완료했습니다!!!"); }
/// <summary> /// 생성자 /// </summary> /// <param name="initialCount">초기 countdown 수 (0보다 크거나 같아야 합니다)</param> /// <param name="action">countdown이 끝나면 (countdown 수가 0가 되면) 수행할 action</param> public ActionCountdownEvent(int initialCount, Action action) { initialCount.ShouldBePositiveOrZero("initialCount"); action.ShouldNotBeNull("action"); _action = action; _event = new CountdownEvent(initialCount); if(initialCount == 0) action(); else _context = ExecutionContext.Capture(); }
/// <summary> /// 지정된 delegate을 lock을 건 상태에서 실행합니다. /// </summary> /// <param name="runUnderLock">실행할 delegate</param> public void Execute(Action runUnderLock) { runUnderLock.ShouldNotBeNull("runUnderLock"); var lockTaken = false; try { Enter(ref lockTaken); runUnderLock(); } finally { if(lockTaken) Exit(); } }
public PeriodInvoker(string periodTimeFormat, TimeSpan idleTimeSpan, Action<object> periodAction, bool startNow = false) { periodAction.ShouldNotBeNull("periodAction"); _periodAction = periodAction; _periodTimeFormat = periodTimeFormat; PeriodTimeSpan = idleTimeSpan; if(IsDebugEnabled) log.Debug("PeriodInvoke가 생성되었습니다. periodTimeFormat=[{0}], periodTimeSpan=[{1}], startNow=[{2}]", _periodTimeFormat, _periodTimeFormat, startNow); if(startNow) Start(); }
/// <summary> /// 특정 수형의 특정 메소드를 호출할 수 있는 <see cref="MethodInvoker"/>를 입력 받아 <paramref name="action"/>을 수행합니다. /// </summary> /// <param name="instanceType"></param> /// <param name="action"></param> /// <param name="methodName"></param> /// <param name="parameterTypes"></param> public static void InvokeMethod(this Type instanceType, Action<MethodInvoker> action, string methodName, params Type[] parameterTypes) { instanceType.ShouldNotBeNull("instanceType"); methodName.ShouldNotBeWhiteSpace("methodName"); action.ShouldNotBeNull("action"); var invoker = GetMethodInvoker(instanceType, methodName, parameterTypes); if(invoker != null) { if(IsDebugEnabled) log.Debug("메소드[{0}]를 수행합니다...", methodName); action(invoker); } }
/// <summary> /// 지정된 함수를 수행하는데 걸리는 시간 (msec)을 검사한다. /// </summary> /// <param name="gabageCollect">시간측정을 더 정밀하게 하기 위해 GabageCollect()를 수행하고 할 것인가?</param> /// <param name="action">시간 측정이 필요한 함수</param> /// <returns>지정된 함수 수행 시간 (milliseconds)</returns> /// <example> /// <code> /// int msec = With.OperationTime(false, /// delegate /// { /// // some code... /// }); /// </code> /// </example> public static double OperationTimer(Action action, bool gabageCollect = false) { action.ShouldNotBeNull("action"); if(gabageCollect) GabageCollect(); var stopwatch = new Stopwatch(); try { stopwatch.Start(); action(); } finally { stopwatch.Stop(); } return stopwatch.ElapsedMilliseconds; }
/// <summary> /// 특정 수형의 특정 메소드를 호출할 수 있는 <see cref="MethodInvoker"/>를 입력 받아 <paramref name="action"/>을 수행합니다. /// </summary> /// <param name="instanceType"></param> /// <param name="fromInclusive"></param> /// <param name="toExclusive"></param> /// <param name="action"></param> /// <param name="methodName"></param> /// <param name="parameterTypes"></param> public static ParallelLoopResult InvokeMethodAsParallel(this Type instanceType, int fromInclusive, int toExclusive, Action<int, MethodInvoker> action, string methodName, params Type[] parameterTypes) { instanceType.ShouldNotBeNull("instanceType"); action.ShouldNotBeNull("action"); var methodInvoker = instanceType.GetMethodInvoker(methodName, DefaultFlags, parameterTypes); if(methodInvoker != null) { if(IsDebugEnabled) log.Debug("메소드[{0}]를 병렬 방식으로 수행합니다...", methodName); return Parallel.For(fromInclusive, toExclusive, i => action(i, methodInvoker)); } return new ParallelLoopResult(); }
/// <summary> /// 반복 주기에 따라 지정된 Action을 비동기 방식으로 작업을 수행합니다. /// </summary> /// <param name="periodTimeFormat">주기 표현식</param> /// <param name="idleTimeSpan">유휴 시간 간격</param> /// <param name="periodAction">주기 도래시 수행할 델리게이트</param> /// <param name="token">취소시 필요한 토큰</param> protected virtual void DoInvokeByPeriodTime(string periodTimeFormat, TimeSpan idleTimeSpan, Action<object> periodAction, CancellationToken token) { periodAction.ShouldNotBeNull("periodAction"); if(IsDebugEnabled) log.Debug("반복 주기에 따라 지정된 Action을 비동기 방식으로 수행하는 작업을 시작합니다... periodTimeFormat=[{0}]", periodTimeFormat); var previousTime = DateTime.MinValue; while(token.IsCancellationRequested == false) { var currentTime = DateTime.Now; if(PeriodTimeFormat.IsExpired(periodTimeFormat, previousTime, currentTime)) { if(IsDebugEnabled) log.Debug("반복 주기에 도래하여, 지정된 Action을 수행을 시작합니다... " + "periodTimeFormat=[{0}], previousTime=[{1}], currentTime=[{2}]", periodTimeFormat, periodAction, currentTime); With.TryActionAsync( () => Task.Factory.StartNew(periodAction, token, TaskCreationOptions.PreferFairness).Wait(token), age => { if(IsDebugEnabled) log.Debug("작업 실행 중에 중단 요청에 의해 실행 취소되었습니다..."); age.Handle(ex => token.IsCancellationRequested); }); previousTime = currentTime; if(IsDebugEnabled) log.Debug("반복 주기에 도래하여, 지정된 Action을 수행을 완료하였습니다!!! " + "periodTimeFormat=[{0}], previousTime=[{1}], currentTime=[{2}]", periodTimeFormat, periodAction, DateTime.Now); } if(token.IsCancellationRequested == false) token.WaitHandle.WaitOne(idleTimeSpan); } }
/// <summary> /// 지정된 Action 들을 하나의 Transaction Scope로 묶어서 처리합니다. /// </summary> /// <param name="actionToExecute">실행할 Action</param> /// <example> /// <code> /// // 한 Tx안에서 3개의 Action 를 수행합니다. /// With.TransactionScope(TransactionScopeOption.Required, /// System.Transactions.IsolationLevel.ReadCommited, /// FindAll_By_DetachedCriteria, /// FindAll_By_Criterion, /// FindAll_By_Example); /// </code> /// </example> public static void TransactionScope(Action actionToExecute) { actionToExecute.ShouldNotBeNull("actionToExecute"); using(var txScope = AdoTool.CreateTransactionScope()) { actionToExecute(); txScope.Complete(); } }
/// <summary> /// 생성자 /// </summary> /// <param name="action">dispose 시에 수행할 action</param> public DisposableAction(Action action) { action.ShouldNotBeNull("action"); Action = action; }
private static Task<bool> SendTaskInternal(SmtpClient client, CancellationToken token, object userToken, Action<TaskCompletionSource<bool>> sendAsyncAction) { client.ShouldNotBeNull("client"); sendAsyncAction.ShouldNotBeNull("sendAsyncAction"); if(IsDebugEnabled) log.Debug("SmtpClient를 이용하여 비동기방식으로 메일을 발송합니다... SmtpHost=[{0}]", client.Host); var tcs = new TaskCompletionSource<bool>(userToken); token.Register(client.SendAsyncCancel); SendCompletedEventHandler handler = null; handler = (s, e) => EventAsyncPattern.HandleCompletion(tcs, e, () => (e.Cancelled == false && e.Error != null), () => client.SendCompleted -= handler); client.SendCompleted += handler; try { sendAsyncAction(tcs); } catch(Exception ex) { client.SendCompleted -= handler; tcs.TrySetException(ex); } return tcs.Task; }
/// <summary> /// 매트릭스에서 각 Cell의 연산을 Wavefront (물결)과 같이, 상위 Cell, 좌측 Cell의 작업이 완료한 후에, 작업하도록 합니다. /// </summary> /// <param name="rows">매트릭스 행 수</param> /// <param name="cols">매트릭스 열 수</param> /// <param name="processCell">매트릭스의 각 셀을 처리할 델리게이트</param> public static void Wavefront(int rows, int cols, Action<int, int> processCell) { rows.ShouldBePositive("rows"); cols.ShouldBePositive("cols"); processCell.ShouldNotBeNull("processCell"); if(IsDebugEnabled) log.Debug("매트릭스 Wavefront 작업을 시작합니다. rows=[{0}], cols=[{1}]", rows, cols); try { // 현재 Cell의 상위 행 (r-1)의 열(column)별 작업 정보 Task[] prevTaskRows = new Task[cols]; // 현재 Cell의 바로 전 작업 (c-1) Task prevTaskInCurrentRow = null; // 현재 cell이 (r,c)일 때, (r-1, c), (r, c-1) 인 cell 의 작업을 나타낸다. var depedencies = new Task[2]; for(var r = 0; r < rows; r++) { prevTaskInCurrentRow = null; for(var c = 0; c < cols; c++) { int i = r, j = c; Task currTask; if(IsDebugEnabled) log.Debug("매트릭스 Wavefront Task 정의 중... Matrix Cell({0},{1})", i, j); if(r == 0 && c == 0) { currTask = Task.Factory.StartNew(() => processCell(i, j)); } else if(r == 0 || c == 0) { // 전 작업 var antecedent = (c == 0) ? prevTaskRows[0] : prevTaskInCurrentRow; currTask = antecedent.ContinueWith(p => { p.Wait(); // 예외 전파를 위해 필요할 뿐 processCell(i, j); }, TaskContinuationOptions.ExecuteSynchronously); } else { depedencies[0] = prevTaskInCurrentRow; // 좌측 cell depedencies[1] = prevTaskRows[c]; // 윗쪽 cell currTask = Task.Factory.ContinueWhenAll(depedencies, ps => { Task.WaitAll(ps); processCell(i, j); }, TaskContinuationOptions.ExecuteSynchronously); } if(IsDebugEnabled) log.Debug("매트릭스 Wavefront Task 정의 완료!!! Matrix Cell({0},{1}), Task Id=[{2}]", i, j, currTask.Id); prevTaskRows[c] = prevTaskInCurrentRow = currTask; } } prevTaskInCurrentRow.Wait(); } catch(AggregateException age) { if(log.IsErrorEnabled) log.Error(age); age.Handle(ex => false); } if(IsDebugEnabled) log.Debug("매트릭스 Wavefront 작업이 완료되었습니다!!!"); }
/// <summary> /// Internet Control Message Protocol (ICMP) echo message 를 비동기적으로 보냅니다. /// </summary> private static Task<PingReply> SendTaskCore(Ping ping, object userToken, Action<TaskCompletionSource<PingReply>> sendAsync) { ping.ShouldNotBeNull("ping"); sendAsync.ShouldNotBeNull("sendAsync"); if(IsDebugEnabled) log.Debug("Ping 작업을 비동기적으로 수행하는 Task를 생성합니다..."); var tcs = new TaskCompletionSource<PingReply>(userToken); PingCompletedEventHandler handler = null; handler = (sender, e) => EventAsyncPattern.HandleCompletion(tcs, e, () => e.Reply, () => ping.PingCompleted -= handler); ping.PingCompleted += handler; try { sendAsync(tcs); } catch(Exception ex) { ping.PingCompleted -= handler; tcs.TrySetException(ex); } return tcs.Task; }
/// <summary> /// Matrix의 모든 요소를 <paramref name="action"/>에 인자로 넣어 실행합니다. /// </summary> /// <param name="m">matrix</param> /// <param name="action">실행할 delegate</param> public static void ForEach(this Matrix m, Action<double> action) { m.ShouldNotBeNull("m"); action.ShouldNotBeNull("action"); for(var r = 0; r < m.Rows; r++) for(var c = 0; c < m.Cols; c++) action(m[r, c]); }
private static IEnumerable<Task> ReadIterator(Stream input, int bufferSize, Action<byte[], int> bufferAvailable) { input.ShouldNotBeNull("input"); bufferSize.ShouldBePositive("bufferSize"); bufferAvailable.ShouldNotBeNull("bufferAvailable"); var buffer = new byte[bufferSize]; while(true) { var readTask = input.ReadAsync(buffer, 0, buffer.Length); yield return readTask; if(readTask.Result <= 0) break; bufferAvailable(buffer, readTask.Result); } }