后台线程和任务

时间:2020-07-17 08:42:23

标签: multithreading .net-core apache-kafka task kafka-consumer-api

我正在尝试找到从专用后台线程运行任务的最佳方法。

Kafka主题消耗了使用上下文,并引发了一个异步事件处理程序来处理ConsumeResult 实例。

Kafka使用者(下面的consumer实例)阻塞线程,直到消息被消耗或传递的CancellationToken被取消为止。

consumeThread = new Thread(Consume)
{
    Name = "Kafka Consumer Thread",
    IsBackground = true,
};

这是我提出的Consume方法的实现,该方法由上面的专用线程启动:

private void Consume(object _)
{
    try
    {
        while (!cancellationTokenSource.IsCancellationRequested)
        {
            var consumeResult = consumer.Consume(cancellationTokenSource.Token);

            var consumeResultEventArgs = new ConsumeResultReceivedEventArgs<TKey, TValue>(
                consumer, consumeResult, cancellationTokenSource.Token);

            _ = Task.Run(async () =>
            {
                if (onConsumeResultReceived is null) continue;

                var handlerInstances = onConsumeResultReceived.GetInvocationList();
                foreach (ConsumeResultReceivedEventHandler<TKey, TValue> handlerInstance in handlerInstances)
                {
                    if (cancellationTokenSource.IsCancellationRequested) return;                        
                    await handlerInstance(this, consumeResultEventArgs).ConfigureAwait(false);                            
                }

            }, cancellationTokenSource.Token);
        }
    }
    catch (OperationCanceledException)
    {

    }
    catch (ThreadInterruptedException)
    {

    }
    catch (ThreadAbortException)
    {
        // Aborting a thread is not implemented in .NET Core.
    }
}

我不确定这是从专用线程运行Task的推荐方法,因此任何建议都将不胜感激。

1 个答案:

答案 0 :(得分:0)

我不清楚为什么您根本需要专用线程。当前的代码将启动一个线程,然后将该线程阻塞以进行消耗,然后在线程池线程上引发事件处理程序。

_ = Task.Run惯用语是“一劳永逸”的做法,从某种意义上讲它会悄悄地吞没事件引发代码或事件处理程序中的任何异常,这是危险的。

我建议将Thread替换为Task.Run,然后直接引发事件处理程序:

consumeTask = Task.Run(ConsumeAsync);

private async Task ConsumeAsync()
{
  while (true)
  {
    var consumeResult = consumer.Consume(cancellationTokenSource.Token);
    var consumeResultEventArgs = new ConsumeResultReceivedEventArgs<TKey, TValue>(
        consumer, consumeResult, cancellationTokenSource.Token);

    if (onConsumeResultReceived is null) continue;

    var handlerInstances = onConsumeResultReceived.GetInvocationList();
    foreach (ConsumeResultReceivedEventHandler<TKey, TValue> handlerInstance in handlerInstances)
    {
      if (cancellationTokenSource.IsCancellationRequested) return;
      await handlerInstance(this, consumeResultEventArgs).ConfigureAwait(false);
    }
  }
}