【问题标题】:.NET BlockingCollection<T> CPU usage.NET BlockingCollection<T> CPU 使用率
【发布时间】:2015-04-23 17:59:33
【问题描述】:

在四核系统中运行此程序将消耗 25% 的 CPU 功率。所以基本上有些东西正在全速运行。我将其缩小到消费者,但负载不会在按下“x”时停止,这应该会终止我的消费者。

我的代码

internal class TestBlockingCollectionConsumerProducer2
{
    private int _itemCount;

    internal void Run()
    {
        BlockingCollection<string> blockingCollection = new BlockingCollection<string>();

        // The token source for issuing the cancelation request.
        CancellationTokenSource cts = new CancellationTokenSource();

        // Simple thread waiting for a Console 'x'
        Task.Factory.StartNew(() =>
        {
            if (Console.ReadKey().KeyChar == 'x')
            {
                cts.Cancel();
            }
        });

        // start producer
        Task.Factory.StartNew(() => Produce(blockingCollection, cts.Token));

        // start multiple consumers
        const int THREAD_COUNT = 5;
        for (int i = 0; i < THREAD_COUNT; i++)
        {
            Task.Factory.StartNew(() => Consume(blockingCollection, cts.Token));
        }

        while (true);
    }

    private void Produce(BlockingCollection<string> blockingCollection, CancellationToken cancellationToken)
    {
        while (true)
        {
            for (int i = 0; i < 10; i++)
            {
                blockingCollection.Add(string.Format("Item {0}", _itemCount++), cancellationToken);
            }

            Console.WriteLine("Added 10 items. Current queue length:" + blockingCollection.Count);
            Thread.Sleep(10000);
        }
    }

    private void Consume(BlockingCollection<string> blockingCollection, CancellationToken cancellationToken)
    {
        try
        {
            foreach (string item in blockingCollection.GetConsumingEnumerable(cancellationToken))
            {
                Console.WriteLine(string.Format("[{0}] Consumer: Consuming: {1}", Thread.CurrentThread.ManagedThreadId, item));
                Thread.Sleep(2500);
            }
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("[{0}] Consumer: Operation has been canceled.", Thread.CurrentThread.ManagedThreadId);
        }
    }
}

我的问题是:
1. 为什么 CPU 负载如此之高? GetConsumingEnumerable() 不应该阻塞,因此根本不使用 CPU 时间?
2. 为什么在 cts.Cancel() 上没有停止?

【问题讨论】:

    标签: c# multithreading asynchronous blockingcollection


    【解决方案1】:

    问题不在于BlockingCollection

    这是while (true); 的无限循环。这是在Run 方法中做什么?这就是烧毁你的 CPU 的原因。

    我看到Produce 方法不尊重CancellationToken。您应该使用while (!cancellationToken.IsCancellationRequested),而不是无限循环。

    另外,对于cts.Cancel,它确实取消了操作。如果由于某种原因这不起作用,请提供一个小而完整的程序来重现问题。

    【讨论】:

    • 我还能如何让应用程序保持活力?从 Main() 调用 Run() - 没什么特别的。
    • @lapsus 见:Task.WaitAll
    • @lapsus 这取决于您希望应用程序保持多长时间。
    • @lapsus :所以你通过让它运行一个无限循环来保持应用程序活着,然后你对使用 CPU 感到惊讶吗?现在我很困惑。如果您在控制台应用程序中,Console.ReadLine() 将阻止,让您准确控制何时关闭应用程序,并且本身不会使用完整的处理器
    • 好的,我明白了。该程序应该作为服务运行 - 所以我不希望它停止。这就是为什么我认为 while(true) 可能是个好主意。我可能应该把这个放到另一个问题中。
    猜你喜欢
    • 2021-12-03
    • 2023-01-10
    • 2021-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多