首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >并行使用ILogger

并行使用ILogger
EN

Stack Overflow用户
提问于 2021-09-29 18:22:56
回答 1查看 341关注 0票数 0

在以下代码中,程序在日志完全刷新之前终止:

代码语言:javascript
复制
    class Program
    {
      static void Main(string[] args)
      {
        var count = -1;
        var tasks = new ConcurrentBag<Task>();

        var services = new ServiceCollection();
        services.AddLogging(configure => configure.AddConsole());
        var serviceProvider = services.BuildServiceProvider();
        var logger = serviceProvider.GetService<ILogger<Program>>();
        if (logger is null)
          throw new NullReferenceException();

        Parallel.ForEach(Enumerable.Range(0, 1000), i =>
        {
          tasks.Add(Task.Run(() => logger.LogInformation(Interlocked.Increment(ref count).ToString())));
          //tasks.Add(Task.Run(() => Console.WriteLine(Interlocked.Increment(ref count).ToString())));
        });

        Task.WhenAll(tasks).Wait();
      }
    }

即使应该打印1.000条日志语句,但只会刷新以下内容:

代码语言:javascript
复制
info: Net5.Program[0]
      6
info: Net5.Program[0]
      2
info: Net5.Program[0]
      5
info: Net5.Program[0]
      1
info: Net5.Program[0]
      7
info: Net5.Program[0]
      4
info: Net5.Program[0]
      3
info: Net5.Program[0]
      0
info: Net5.Program[0]
      8
info: Net5.Program[0]
      10

C:\Users\MyName\source\repos\ConsoleApp\Net5\bin\Debug\net5.0\Net5.exe (process 28048) exited with code 0.
Press any key to close this window . . .

然而,当使用Console.WriteLine (在上面的代码中注释掉)时,所有的行都会被打印出来,这导致人们怀疑控制台记录器在幕后是异步的。

如何确保等待所有日志语句而不需要手动延迟?

编辑:

我决定使用以下代码,这就达到了目的:

代码语言:javascript
复制
class Program
{
  static void Main(string[] args)
  {
    var count = -1;

    var services = new ServiceCollection();
    services.AddLogging(configure => configure.AddConsole());
    using var serviceProvider = services.BuildServiceProvider();
    var logger = serviceProvider.GetRequiredService<ILogger<Program>>();

    var tasks = Enumerable.Range(0, 50000)
      .AsParallel()
      .Select(_ => Task.Run(() => logger.LogInformation(Interlocked.Increment(ref count).ToString())));

    Task.WhenAll(tasks).Wait();
  }
}

主要区别:

  • 服务提供者被释放,这解决了日志刷新问题。
  • 通过使用GetRequiredService获取ILogger实例以避免空检查。
  • 使用Enumerable.Range(...).AsParallel.Select(...)代替Parallel.ForEach来始终坚持执行任务。H 215F 216
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-09-29 18:38:59

如果您释放服务提供者,它将释放所有的单例服务,这将刷新记录器。

也没有必要使用Parallel.ForEach。实际上,将Parallel.ForEachasync``await结合使用是一种代码嗅探。这几乎总是错的。

而且,由于您标记了问题.NET 5.0,您可以将代码更改为:

代码语言:javascript
复制
class Program
{
    static async Task Main()
    {
        var count = -1;
        var tasks = new ConcurrentBag<Task>();

        var services = new ServiceCollection();
        services.AddLogging(configure => configure.AddConsole());
        using var serviceProvider = services.BuildServiceProvider();
        var logger = serviceProvider.GetRequiredService<ILogger<Program>>();

        for (var i = 0; i < 1000; i++)
        {
            tasks.Add(Task.Run(() => logger.LogInformation(Interlocked.Increment(ref count).ToString())));
        };

        await Task.WhenAll(tasks);
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69381601

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档