private void Run(Action <object> action, int count) { for (int i = 0; i < count; i++) { ServiceTasks.Add(Task.Factory.StartNew(action, Token, TaskCreationOptions.LongRunning)); } }
/// <summary> /// Второй этап запуска - стартуем асинхронные задачи /// </summary> /// <returns></returns> private void RunAfterInit() { if (CurrentDeviceSettings.UseKKT) { CashDeskHelper.CashDesk_Init(); } MDB.ConnectMDBSerialPort(CashDeskDeviceID); I2c_Init(); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed ServiceTasks.UpdateWaterCounter(0); ServiceTasks.UpdateCashCounter(0, 0, 0, 0); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed AddItemToLogBox("Управляющее устройство успешно инициализировано, продолжаем..."); int initdelaymillisec = 10000; //подождем немного, винде нужно время, чтобы выделить память, отсвопиться своим гавном //на SD-карту и успокоиться. while (initdelaymillisec > 0) { AddItemToLogBox("Ожидание запуска задач " + (initdelaymillisec / 1000).ToString() + "с..."); int count = 0; while (count < 100) { Task.Delay(100).Wait(); count++; } initdelaymillisec -= 10000; } //Task.Run(CCC, GlobalCancellationTokenSource.Token); ServiceTasks.StartAll(); AddItemToLogBox("Задачи запущены"); Task.Run(MDBHelper.Init_MDB); }
private static void Main(string[] args) { XmlConfigurator.Configure(); var stopWatch = new Stopwatch(); stopWatch.Start(); for (int i = 0; i < nTicks; i++) { //log.Info("A tick! Value: 2, Unit: Bytes, Unit: Kilobytes"); log.Info("A tick! Value: 29.4 Kilobytes"); //log.Info("A tick! Value: 0 Kilobytes"); //log.Info(String.Format("A tick! Timestamp: {0}", DateTimeOffset.Now.AddMinutes(-10).ToString())); //log.Info(null); //log.Info("A tick! %logger %metadata{instanceid}"); log.Info(new AWSAppender.CloudWatch.Model.MetricDatum("A tick!") //.WithTimestamp(DateTimeOffset.Now.AddMinutes(-10)) .WithUnit("Kilobytes") .WithValue(29.4)); } stopWatch.Stop(); Console.WriteLine("All {0} ticks in {1} ms.\nWaiting for requests to complete.", nTicks, stopWatch.ElapsedMilliseconds); stopWatch.Start(); ServiceTasks.WaitForPendingRequests(); stopWatch.Stop(); Console.WriteLine("Requests completed in {0} ms.", stopWatch.ElapsedMilliseconds); }
private static void Main(string[] args) { XmlConfigurator.Configure(); var streams = new[] { "Stream1", "Stream2" }; var groups = new[] { "GRoup1", "GRaoup2" }; var random = new Random(); var stopWatch = new Stopwatch(); stopWatch.Start(); for (int i = 0; i < nTicks; i++) { //log.Info("A tick! Value: 2, Unit: Bytes, Unit: Kilobytes"); if (random.Next(2) == 0) { log.InfoFormat("A tick! Groupname: {0} Streamname: {1} Gauge: {2}", groups[random.Next(2)], streams[random.Next(2)], random.Next(200)); } else { log.Info(new LogDatum("A tick!") { GroupName = groups[random.Next(2)], StreamName = streams[random.Next(2)], Timestamp = DateTime.UtcNow }); } log.Info("Message: sample text for logging"); Thread.Sleep(10); } ILoggerRepository rep = LogManager.GetRepository(); foreach (IAppender appender in rep.GetAppenders()) { var buffered = appender as BufferingAppenderSkeleton; if (buffered != null) { buffered.Flush(); } } stopWatch.Stop(); Console.WriteLine("All {0} ticks in {1} ms.\nWaiting for requests to complete.", nTicks, stopWatch.ElapsedMilliseconds); stopWatch.Start(); ServiceTasks.WaitForPendingRequests(); stopWatch.Stop(); Console.WriteLine("Requests completed in {0} ms.", stopWatch.ElapsedMilliseconds); }
/// <summary> /// Монета помещена в кэшбокс /// </summary> /// <param name="CoinValue"></param> private static void CashDevices_MDBInsertedCoinRoutedToCashBox(double CoinValue) { StartPage.AddItemToLogBox("Монета помещена в кэшбокс ₽" + CoinValue.ToString("N2")); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed ServiceTasks.UpdateCashCounter(1, CoinValue, 0, 0); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed if ((StartPage.CurrentState == StartPage.States.ReadyToServe) || (StartPage.CurrentState == StartPage.States.ReadyToDispenseWater)) { StartPage.UserDeposit += CoinValue; } }
/// <summary> /// Вставлена купюра /// </summary> /// <param name="BillValue"></param> private static void CashDevices_MDBInsertedBill(double BillValue) { StartPage.AddItemToLogBox("Прием купюры ₽" + BillValue.ToString("N2")); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed ServiceTasks.UpdateCashCounter(0, 0, 1, (int)BillValue); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed if ((StartPage.CurrentState == StartPage.States.ReadyToServe) || (StartPage.CurrentState == StartPage.States.ReadyToDispenseWater)) { StartPage.UserDeposit += BillValue; } }
private static void Main(string[] args) { XmlConfigurator.Configure(); var stopWatch = new Stopwatch(); stopWatch.Start(); for (int i = 0; i < nTicks; i++) { log.Info("A log event"); } stopWatch.Stop(); Console.WriteLine(String.Format("All {0} ticks in {1} ms.\nWaiting for requests to complete.", nTicks, stopWatch.ElapsedMilliseconds)); stopWatch.Start(); ServiceTasks.WaitForPendingRequests(); stopWatch.Stop(); Console.WriteLine(String.Format("Requests completed in {0} ms.", stopWatch.ElapsedMilliseconds)); }
public WebServiceResponse ExecuteTask(string TaskNames) { if (!string.IsNullOrEmpty(TaskNames)) { TaskNames = TaskNames.Trim(); } var result = new WebServiceResponse(); result.Status = (int)0;// ErrorCodes.ALL_OK; result.Message = "Success"; try { ServiceTasks.DoTasks(TaskNames); } catch (Exception ex) { result.Status = (int)1;// ErrorCodes.GENERAL_ERROR; result.Message = ex.Message; ServiceLogger.Error("ExecuteTask error: " + ex.Message); } return(result); }
/// <summary> /// выдаем сдачу пока депозит не станет равен 0 /// </summary> private void DispenseChange() { ChangeModeSemaphore.Wait(); if (StartPage.CurrentState != StartPage.States.DispenseChange) { ChangeModeSemaphore.Release(); return; } #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { dispenselabel.Text = Math.Round(StartPage.UserDeposit, 0, MidpointRounding.AwayFromZero).ToString().PadLeft(3, '0'); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed if (StartPage.CurrentDeviceSettings.UseKKT && Math.Round(StartPage.CurrentSaleSession.Quantity, 3) > 0) { try { StartPage.CurrentSaleSession.ReceiptNumber = StartPage.SystemState.KKTReceiptNextNumber; StartPage.CurrentSaleSession.StageNumber = Convert.ToInt16(StartPage.SystemState.KKTStageNumber); StartPage.CurrentSaleSession.TaxSystemInUse = StartPage.CurrentDeviceSettings.TaxSystem; if (Math.Round(StartPage.UserDeposit, 2, MidpointRounding.AwayFromZero) == 0) { CashDesk.PrintReceipt(GlobalVars.ReceiptLinesToPrint, (((int)(Math.Round(StartPage.CurrentSaleSession.UserCash, 2) * 100)) * 1.00 / StartPage.CurrentSaleSession.PRICE_PER_ITEM_MDE), StartPage.CurrentSaleSession.PRICE_PER_ITEM_MDE, (int)(Math.Round(StartPage.CurrentSaleSession.UserCash, 2) * 100)); } else { CashDesk.PrintReceipt(GlobalVars.ReceiptLinesToPrint, Math.Round(StartPage.CurrentSaleSession.Quantity, 3), StartPage.CurrentSaleSession.PRICE_PER_ITEM_MDE, (int)(Math.Round(StartPage.CurrentSaleSession.UserCash, 2) * 100)); } } catch { } } Task.Delay(15000).Wait(); try { CashDesk.GetCurrentStageParameters(); StartPage.CurrentSaleSession.ActualChangeDispensed = (int)Math.Round(StartPage.UserDeposit, 0, MidpointRounding.AwayFromZero); StartPage.CurrentSaleSession.ChangeActualDiff = StartPage.CurrentSaleSession.ActualChangeDispensed - StartPage.UserDeposit; StartPage.CurrentSaleSession.CompleteSession(); ServiceTasks.UpdateWaterCounter(StartPage.CurrentSaleSession.Quantity); StartPage.UserDeposit = Math.Round(StartPage.UserDeposit, 0, MidpointRounding.AwayFromZero); while ((int)StartPage.UserDeposit > 0) { while (MDB.DispenseInProgress || MDB.CheckDispenseResult) { Task.Delay(1000).Wait(); } int _change = (int)StartPage.UserDeposit; if (_change > 127)//не более 127 рублей в одной порции сдачи, ограничение монетоприемника { _change = 127; } MDB.Dispensetimeout = DateTime.Now.AddSeconds(10); MDB.PayoutCoins(_change);//выдаем сдачу монетами StartPage.UserDeposit -= _change; Task.Delay(2000).Wait(); } string oosfilename = ApplicationData.Current.LocalFolder.Path + "\\" + GlobalVars.HardWareID + ".031"; if (File.Exists(oosfilename)) { StartPage.CurrentState = StartPage.States.OutOfService; #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(OutOfServicePage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed return; } StartPage.CurrentState = StartPage.States.ReadyToServe; MDB.EnableCashDevices(); #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(MainPage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } catch { } ChangeModeSemaphore.Release(); }
public ServiceTest() : base("ThinkAway.Test") { ServiceTasks.Add(new MyTask(30, false)); }
protected override void OnStart(string[] args) { try { //if (!SecureWebConfig.Secured) //{ // SecureWebConfig.Secure(); //} } catch (Exception ex) { ServiceLogger.Error("Configuration cannot be read, reason: " + ex.Message); } ServiceTasks.LoadConfig(); // collect and pass back the list of known types WebServiceKnownTypesProvider.KnownTypes.Add(typeof(WebServiceStatus)); oServiceHost = new ServiceHost(oServiceType); try { if (oServiceHost.BaseAddresses.Count == 0) { string ba = DefaultHTTPUrl; //ExtensionHelpers.GetConfigString("WebServiceBaseURL"); if (string.IsNullOrEmpty(ba)) { if (UseHTTPS) { ba = DefaultHTTPSUrl; } else { ba = DefaultHTTPUrl; } } else { if (ba.Contains("http://")) { UseHTTPS = false; } } var baseAddresses = new Uri[] { new Uri(ba) }; oServiceHost = new ServiceHost(oServiceType, baseAddresses); var endpoint = CreateEndpoint(oServiceInterfaceType, ba); oServiceHost.AddServiceEndpoint(endpoint); ServiceMetadataBehavior metadataBehavior = new ServiceMetadataBehavior(); //metadataBehavior.HttpGetEnabled = true; oServiceHost.Description.Behaviors.Add(metadataBehavior); } oServiceHost.Authorization.ServiceAuthorizationManager = new RestAuthorizationManager(); oServiceHost.Open(); } catch (Exception ex) { ServiceLogger.Error("Service cannot be started, reason: " + ex.Message); return; } //Tasks.StartTimer(); StartHTTPCompanionService(oServiceHost.BaseAddresses[0].ToString()); ServiceLogger.Info("SERVICE STARTED"); foreach (var uri in oServiceHost.BaseAddresses) { ServiceLogger.Info("Listening on: " + uri); } }
/// <summary> /// Обрабатываем сведения о состоянии трубок монетоприемника /// </summary> private static void CashDevices_MDBCCTubesStatus(List <MDB.CoinChangerTubeRecord> CoinChangerTubeRecords) { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed ServiceTasks.UpdateCashCounter(0, 0, 0, 0, CoinChangerTubeRecords.First(x => (int)x.CoinValue == 1).CoinsCount, CoinChangerTubeRecords.First(x => (int)x.CoinValue == 2).CoinsCount, CoinChangerTubeRecords.First(x => (int)x.CoinValue == 5).CoinsCount, CoinChangerTubeRecords.First(x => (int)x.CoinValue == 10).CoinsCount); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed }
public override void Start() { ServiceTasks.Add(Task.Factory.StartNew(ProcessPackets, Token, TaskCreationOptions.LongRunning)); ServiceTasks.Add(Task.Factory.StartNew(PopulateOutputCache, Token, TaskCreationOptions.LongRunning)); }
private static void Main(string[] args) { XmlConfigurator.Configure(); var queues = new[] { "Queue1", "Queue2" }; var random = new Random(); var stopWatch = new Stopwatch(); stopWatch.Start(); for (int i = 0; i < nTicks; i++) { //log.Info("A tick! Value: 2, Unit: Bytes, Unit: Kilobytes"); switch (random.Next(4)) { case 0: log.InfoFormat("A tick! Queuename: {0} ID: {1}", "queue0", random.NextDouble().ToString(CultureInfo.InvariantCulture).Replace(".", "")); break; case 1: log.InfoFormat("A tick! Queuename: {0} ID: {1} DelaySeconds: {2}", "queue1", random.NextDouble().ToString(CultureInfo.InvariantCulture).Replace(".", ""), random.Next(10)); break; case 2: log.Info(new SQSDatum("A tick!") { QueueName = "queue2", ID = random.NextDouble().ToString(CultureInfo.InvariantCulture).Replace(".", "") }); break; case 3: log.Info(new SQSDatum("A tick!") { QueueName = "queue3", ID = random.NextDouble().ToString(CultureInfo.InvariantCulture).Replace(".", ""), DelaySeconds = random.Next(10) + 10 }); break; } //Thread.Sleep(10); } ILoggerRepository rep = LogManager.GetRepository(); foreach (IAppender appender in rep.GetAppenders()) { var buffered = appender as BufferingAppenderSkeleton; if (buffered != null) { buffered.Flush(); } } stopWatch.Stop(); Console.WriteLine("All {0} ticks in {1} ms.\nWaiting for requests to complete.", nTicks, stopWatch.ElapsedMilliseconds); stopWatch.Start(); ServiceTasks.WaitForPendingRequests(); stopWatch.Stop(); Console.WriteLine("Requests completed in {0} ms.", stopWatch.ElapsedMilliseconds); }
public override void Start() { _cancelUdpClient.Reset(); ServiceTasks.Add(Task.Factory.StartNew(ReceivePackets, Token, TaskCreationOptions.LongRunning)); }
/// <summary> /// выдаем сдачу пока депозит не станет равен 0 /// </summary> private void DispenseChange() { ChangeModeSemaphore.Wait(); if (StartPage.CurrentState != StartPage.States.DispenseChange) { ChangeModeSemaphore.Release(); return; } #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { dispenselabel.Text = Math.Round(StartPage.UserDeposit, 0, MidpointRounding.AwayFromZero).ToString().PadLeft(3, '0'); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed if (StartPage.CurrentDeviceSettings.UseKKT && Math.Round(StartPage.CurrentSaleSession.Quantity, 3) > 0) { try { StartPage.CurrentSaleSession.ReceiptNumber = StartPage.SystemState.KKTReceiptNextNumber; StartPage.CurrentSaleSession.StageNumber = Convert.ToInt16(StartPage.SystemState.KKTStageNumber); StartPage.CurrentSaleSession.TaxSystemInUse = StartPage.CurrentDeviceSettings.TaxSystem; if (Math.Round(StartPage.UserDeposit, 2, MidpointRounding.AwayFromZero) == 0) { CashDesk.PrintReceipt(GlobalVars.ReceiptLinesToPrint, (((int)(Math.Round(StartPage.CurrentSaleSession.UserCash, 2) * 100)) * 1.00 / StartPage.CurrentSaleSession.PRICE_PER_ITEM_MDE), StartPage.CurrentSaleSession.PRICE_PER_ITEM_MDE, (int)(Math.Round(StartPage.CurrentSaleSession.UserCash, 2) * 100)); } else { CashDesk.PrintReceipt(GlobalVars.ReceiptLinesToPrint, Math.Round(StartPage.CurrentSaleSession.Quantity, 3), StartPage.CurrentSaleSession.PRICE_PER_ITEM_MDE, (int)(Math.Round(StartPage.CurrentSaleSession.UserCash, 2) * 100)); } } catch { } } while (CashDesk.PendingTasks.Count(x => x.Status != CashDesk.KKTTaskStatus.Completed) > 0) { Task.Delay(100).Wait(); } try { CashDesk.GetCurrentStageParameters(); ServiceTasks.UpdateWaterCounter(StartPage.CurrentSaleSession.Quantity); StartPage.UserDeposit = Math.Round(StartPage.UserDeposit, 0, MidpointRounding.AwayFromZero); int ExpectedDeposit = (int)StartPage.UserDeposit; while ((int)StartPage.UserDeposit > 0) { while (MDB.DispenseInProgress || MDB.AwaitDispenseResult) { Task.Delay(1000).Wait(); } if (ExpectedDeposit == (int)StartPage.UserDeposit) { ExpectedDeposit = (int)StartPage.UserDeposit - (int)StartPage.UserDeposit & 0x7f; MDB.PayoutCoinsAsync((int)StartPage.UserDeposit & 0x7f).Wait();//выдаем сдачу монетами, не более 127 рублей за раз } else { if ((int)StartPage.UserDeposit > 0) { //это не очень хорошая ситуация, часть сдачи или всю мы не отдали, //либо отдали, но монетоприемник не прислал об этом никакой информации по какой-то причине //в отведенное для этого время (см MDBHelper.CashDevices_MDBChangeDispensed). //Информация об этом будет видна в личном кабинете, в таблице продаж отражается //выданная сдача и разница между расчетным и реальнно выданным значением. //Если монетоприемник пришлет ошибку, автомат перейдет в режим OutOfService автоматически (см MDBHelper.CashDevices_MDBError) //выходим из процедуры выдачи сдачи, не будем разбрасывать зря бабло. break; } } } } catch { } finally { StartPage.CurrentSaleSession.ChangeActualDiff = StartPage.CurrentSaleSession.ActualChangeDispensed - StartPage.CurrentSaleSession.UserCash; //пишем разницу между расчетным и реальнно выданным значением сдачи StartPage.CurrentSaleSession.CompleteSession(); //закрываем продажу string oosfilename = ApplicationData.Current.LocalFolder.Path + "\\" + GlobalVars.HardWareID + ".031"; if (File.Exists(oosfilename)) { StartPage.CurrentState = StartPage.States.OutOfService; #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(OutOfServicePage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } else { StartPage.CurrentState = StartPage.States.ReadyToServe; #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed MDB.EnableCashDevicesAsync(); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = Window.Current.Content as Frame; frame.Navigate(typeof(MainPage)); }); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } ChangeModeSemaphore.Release(); } }
public override void Start() { ServiceTasks.Add(Task.Factory.StartNew(ReceivePackets, Token, TaskCreationOptions.LongRunning)); }
/// <summary> /// Обрабатываем сведения о состоянии трубок монетоприемника /// </summary> /// <param name="RUR1"></param> /// <param name="RUR2"></param> /// <param name="RUR5"></param> /// <param name="RUR10"></param> private static void CashDevices_MDBCCTubesStatus(int RUR1, int RUR2, int RUR5, int RUR10) { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed ServiceTasks.UpdateCashCounter(0, 0, 0, 0, RUR10, RUR5, RUR2, RUR1); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed }
public override void Start() { ServiceTasks.Add(Task.Factory.StartNew(RunSender, Token, TaskCreationOptions.LongRunning)); }
private void Button_Click_1(object sender, RoutedEventArgs e) { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed ServiceTasks.UpdateCashCounter(1, 0.5, 1, 100, 2, 1, 3, 1); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed }
private static void Main(string[] args) { XmlConfigurator.Configure(); var dims = new[] { "TestDimenValue1", "TestDimenValue2" }; var names = new[] { "TestName1", "TestName2" }; var nss = new[] { "TestNameSpace1", "TestNameSpace2" }; var units = new[] { "Kilobytes", "Megabytes", "Gigabytes" }; var random = new Random(); var stopWatch = new Stopwatch(); stopWatch.Start(); for (int i = 0; i < nTicks; i++) { //log.Info("A tick! Value: 2, Unit: Bytes, Unit: Kilobytes"); if (random.Next(2) == 0) { log.InfoFormat("A tick! Namespace: {1} MetricCOMMENTName: {2} Dimension: TestDim: {3} Value: {0} {4}", random.NextDouble() * (1e5 - 1e2) + 1e2, nss[random.Next(2)], names[random.Next(2)], dims[random.Next(2)], units[random.Next(3)]); } else { log.Info(new CloudWatchAppender.Model.MetricDatum("A tick!") { NameSpace = nss[random.Next(2)], Dimensions = { new Dimension { Name = "TestDim", Value = dims[random.Next(2)] } }, //MetricName = names[random.Next(2)], Unit = units[random.Next(3)], StatisticValues = new StatisticSet { Minimum = random.NextDouble() * (3e3 - 1e2) + 1e2, Maximum = random.NextDouble() * (1.1e5 - .9e4) + .9e4, Sum = (random.NextDouble() * (6e4 - 4e4) + 4e4) * 100, SampleCount = 100 } }); } Thread.Sleep(10); } ILoggerRepository rep = LogManager.GetRepository(); foreach (IAppender appender in rep.GetAppenders()) { var buffered = appender as BufferingAppenderSkeleton; if (buffered != null) { buffered.Flush(); } } stopWatch.Stop(); Console.WriteLine("All {0} ticks in {1} ms.\nWaiting for requests to complete.", nTicks, stopWatch.ElapsedMilliseconds); stopWatch.Start(); ServiceTasks.WaitForPendingRequests(); stopWatch.Stop(); Console.WriteLine("Requests completed in {0} ms.", stopWatch.ElapsedMilliseconds); }