【问题标题】:Multithreaded loop does not work on IIS多线程循环在 IIS 上不起作用
【发布时间】:2018-08-10 10:36:06
【问题描述】:

这将是非常基本的,但我们遇到了问题并且无法缩小问题范围。希望有人能对此有所了解。

我们有一个简单的静态类

public static class SomeLogger
{
    private static ConcurrentQueue<LogObject> queue = new ConcurrentQueue<LogObject>();
    private static bool isRunning = false;        
    public static void Start()
    {
        if (isRunning) return;
        Task.Run(() => Process());
    }
    public static void Stop()
    {
        isRunning = false;
    }

    public static void AddToQueue(LogObject obj)
    {
        queue.Enqueue(obj);
    }

    public static void Process()
    {
        isRunning = true;

        using (var p = new SomeClass())
        {
            while (isRunning)
            {
                //see if something is in the queue object if yes process it 
                if(queue.TryDequeue(out LogObject d))
                {
                    //Do some stuff
                }
                Thread.Sleep(1000);
            }
        }
    }
}

我们在开始时在应用程序事件监听器中调用这个类 - 它调用 SomeLogger.Start - 将 isRunning 设置为 true

到目前为止一切都很好

我们运行 Web 应用程序并多次调用 SomeLogger.Add() 来进行日志记录

但是当我们在本地运行时,即在 iisexpress 上,while 循环会拾取所有添加队列事件并处理它们。

虽然在我们服务器上的 IIS 上执行相同的操作,但只有来自队列的第一个 Add 和 Last Add 消息被选中。??

我们不知道为什么?你们在上面的代码中看到的任何错误..

环境: 简单的 Asp.Net Web API SomeClass 是一个 kafka 生产者

【问题讨论】:

  • 什么是// do some stuff?确定没有抛出异常?
  • 我没有在代码中看到你重置isRunning的任何地方。
  • 可能不是解决方案,但您可能希望将 if (queue.TryDequeue(...)) 替换为 while (queue.TryDequeue(...))。
  • 我没有发现任何问题,并且同意 Patrick 的观点,即问题可能出在处理逻辑上。只是建议使用Task.Delay(1000).Wait() 而不是Thread.Sleep(1000) 以保持一致性,我会将Process() 方法设为私有。尽管很抱歉,但这与您的问题无关。由于这发生在服务器上而不是本地上,因此可能是连接问题。你能确认AddToQueue 每次通话都会被击中吗?感觉代码是好人,所以我的猜测是像帕特里克所说的那样有错误。
  • 其他想法:您可能还想用 Task.Delay() 替换 Thread.Sleep() 语句,因为 Thread.Sleep() 会阻塞 Thread,然后不能将其用于其他任何事情.

标签: c# asp.net multithreading


【解决方案1】:

这是使用 TPL 的 Dataflow 库的解决方案

public static class SomeLogger
{
    private static readonly BufferBlock<LogObject> _buffer = new BufferBlock<LogObject>();
    private static Task _consumer;
    private static CancellationTokenSource _cts;

    public static void Start()
    {
        if (_cts != null && !_cts.IsCancellationRequested) return;

        _cts = new CancellationTokenSource();
        _consumer = ConsumeAsync(_buffer, _cts.Token);
    }

    public static void Stop()
    {
        _cts.Cancel();
    }

    public static void AddToQueue(LogObject log)
    {
        SendToBuffer(_buffer, log);
    }

    private static void SendToBuffer(ITargetBlock<LogObject> target, LogObject log)
    {
        target.Post(log);
    }

    private static async Task ConsumeAsync(IReceivableSourceBlock<LogObject> source, CancellationToken cancellationToken)
    {
        while (await source.OutputAvailableAsync(cancellationToken))
        {
            var log = await source.ReceiveAsync();

            // do some stuff
        }
    }

您甚至可以使用 AddToQueue 添加到缓冲区,直到调用 Start 才会处理它们

【讨论】:

  • 这个解决了什么问题?
猜你喜欢
  • 1970-01-01
  • 2014-06-17
  • 1970-01-01
  • 1970-01-01
  • 2010-12-06
  • 2019-06-04
  • 2020-06-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多