Exemple #1
0
        private async Task LoadStocksFromStocksService()
        {
            try
            {
                var service = new StocksService();
                var data    = await service.GetStockPricesFor(Ticker.Text, cancellationTokenSource.Token);

                Stocks.ItemsSource = data;
            }
            catch (Exception ex)
            {
                Notes.Text += ex.InnerException.Message + Environment.NewLine;
            }
        }
Exemple #2
0
        private async Task ProcessStocksOnArrival()
        {
            try
            {
                var tickers = Ticker.Text.Split(',', ' ');

                var service = new StocksService();
                var stocks  = new ConcurrentBag <StockPrice>();

                var tickerLoadingTasks = new List <Task <IEnumerable <StockPrice> > >();

                foreach (var ticker in tickers)
                {
                    var loadtask = service.GetStockPricesFor(ticker, cancellationTokenSource.Token)
                                   .ContinueWith(t =>
                    {
                        foreach (var stock in t.Result.Take(5))
                        {
                            // stocks collection can be safely used with different threads
                            stocks.Add(stock);
                        }
                        Dispatcher.Invoke(() =>
                        {
                            Stocks.ItemsSource = stocks.ToArray();
                        });

                        return(t.Result);
                    });

                    tickerLoadingTasks.Add(loadtask);
                }
                await Task.WhenAll(tickerLoadingTasks);
            }
            catch (Exception ex)
            {
                Notes.Text += ex.Message + Environment.NewLine;
            }
            finally
            {
                cancellationTokenSource = null;
            }
        }
Exemple #3
0
        private async void Search_Click(object sender, RoutedEventArgs e)
        {
            #region Before loading stock data
            var watch = new Stopwatch();
            watch.Start();
            StockProgress.Visibility      = Visibility.Visible;
            StockProgress.IsIndeterminate = true;

            Search.Content = "Cancel";
            #endregion

            #region Cancellation
            if (cancellationTokenSource != null)
            {
                cancellationTokenSource.Cancel();
                cancellationTokenSource = null;
                return;
            }

            cancellationTokenSource = new CancellationTokenSource();

            cancellationTokenSource.Token.Register(() =>
            {
                Notes.Text += "Cancellation requested" + Environment.NewLine;
            });
            #endregion

            try
            {
                #region Load One or Many Tickers
                var tickers = Ticker.Text.Split(',', ' ');

                var service = new StocksService();

                var tickerLoadingTasks = new List <Task <IEnumerable <StockPrice> > >();
                foreach (var ticker in tickers)
                {
                    var loadTask = service.GetStockPricesFor(ticker, cancellationTokenSource.Token);

                    tickerLoadingTasks.Add(loadTask);
                }
                #endregion

                // Stocks loaded - now need processing
                var loadedStocks = await Task.WhenAll(tickerLoadingTasks);

                // Use threadsafe collection
                var values = new ConcurrentBag <StockCalculation>();

                // Standard foreach loop converted into a Parallel foreach
                // Includes guidance on max number of concurrent tasks
                var exResult = Parallel.ForEach(loadedStocks,
                                                new ParallelOptions {
                    MaxDegreeOfParallelism = 4
                },
                                                (stocks, state) =>
                {
                    var stockName = stocks.First().Ticker;

                    // Will break out of current thread
                    // Will not execute outstanding iterations
                    // On-going tasks will not be stopped
                    // return - explicitly return from current thread context
                    if (stockName == "MBI")
                    {
                        state.Break();
                        return;
                    }

                    var result = CalculateExpensiveComputation(stocks);
                    var data   = new StockCalculation
                    {
                        Ticker = stocks.First().Ticker,
                        Result = result
                    };

                    values.Add(data);
                });

                if (exResult.IsCompleted)
                {
                    Stocks.ItemsSource = values;
                }
                else
                {
                    Notes.Text = "Parallel computation of stocks did not complete successfully";
                }

                // Calculate total stock price for each ticker
                decimal totalStocksValue = 0;
                exResult = Parallel.For(0, loadedStocks.Length, i =>
                {
                    var value = 0m;
                    foreach (var s in loadedStocks[i])
                    {
                        // 1. Unstable: totalStocksValue += Compute(s);
                        // 2. Fix, but limited solution:
                        // Interlocked.Add(ref totalStocksValue, (int)Compute(s));
                        // 3. Minimise code inside lock
                        value += Compute(s);
                    }
                    lock (syncRoot)
                    {
                        totalStocksValue += value;
                    }
                });

                Notes.Text = $"Stock price total: {totalStocksValue:N2}";
            }
            catch (Exception ex)
            {
                Notes.Text += ex.Message + Environment.NewLine;
            }
            finally
            {
                cancellationTokenSource = null;
            }

            #region After stock data is loaded
            StocksStatus.Text        = $"Loaded stocks for {Ticker.Text} in {watch.ElapsedMilliseconds}ms";
            StockProgress.Visibility = Visibility.Hidden;
            Search.Content           = "Search";

            #endregion
        }