Пример #1
0
        public void Throttle_CanPreventConcurrentRequests()
        {
            // no more than 2 concurrent threads.
            ThrottleConfiguration configuration = new ThrottleConfiguration
            {
                MaxConcurrentThreads = 2
            };
            Throttle throttle = new Throttle(configuration);

            Task[] threads = new Task[5];

            ManualResetEvent awaiter = new ManualResetEvent(false);

            CancellationTokenSource outerCancellationSource = new CancellationTokenSource(5 * 1000); // 5 seconds

            long success = 0;

            for (int i = 0; i < threads.Length; i++)
            {
                int       instance = i;
                Stopwatch sw       = new Stopwatch();
                sw.Start();
                threads[i] = Task.Run(async() => {
                    CancellationTokenSource innerCancellationSource = CancellationTokenSource.CreateLinkedTokenSource(
                        outerCancellationSource.Token,
                        new CancellationTokenSource(5 * 1000).Token  // 5 seconds
                        );
                    Log.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] Instance {instance}: thread activated (activateTime: {sw.Elapsed})");
                    sw.Restart();
                    awaiter.WaitOne();
                    Log.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] Instance {instance}: thread started (runTime: {sw.Elapsed})");

                    try
                    {
                        IDisposable lease = await throttle.AcquireLeaseAsync(innerCancellationSource.Token);
                        using (lease)
                        {
                            Log.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] Instance {instance}: acquired lease (threads: {throttle.ActiveThreads}, runTime: {sw.Elapsed})");

                            await Task.Delay(1000, innerCancellationSource.Token); // do some work

                            Log.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] Instance {instance}: completed work (runTime: {sw.Elapsed})");

                            Assert.True(throttle.ActiveThreads <= configuration.MaxConcurrentThreads, $"Instance {instance}: Thread count exceeds max concurrent threads (actual: {throttle.ActiveThreads}, max: {configuration.MaxConcurrentThreads})");
                        }
                        long current = Interlocked.Increment(ref success);
                        Log.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] Instance {instance}: thread complete (runTime: {sw.Elapsed}, success: {current})");
                    }
                    catch (Exception ex)
                    {
                        Log.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] Instance {instance}: thread failed (runTime: {sw.Elapsed}) {ex}");
                        throw new Exception("Operation failed", ex);
                    }
                });
            }

            Log.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] set.....");
            awaiter.Set();
            Task.WaitAll(threads, outerCancellationSource.Token);

            Log.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] complete.....");
            long actual = Interlocked.Read(ref success);

            Assert.Equal(threads.Length, actual);
        }