控制台应用程序/Windows 服务中的 Async/Await 或 Task.Run

2024-02-06

我一直在研究(包括查看有关此主题的所有其他 SO 帖子)实现(最有可能的)Windows 服务工作线程的最佳方法,该工作线程将从数据库中提取工作项并在“即发即用”中异步并行处理它们。 -forget'方式在后台运行(工作项管理将全部以异步方式处理)。工作项将是 Web 服务调用和数据库查询。这些工作项的生产者将会受到一些限制,以确保采用某种衡量方法来安排工作。下面的示例非常基础,只是为了突出显示 while 循环和 for 循环的逻辑。哪种方法是理想的方法还是无关紧要?有没有更合适/更高效的方法来实现这一目标?

异步/等待...

    private static int counter = 1;

    static void Main(string[] args)
    {
        Console.Title = "Async";

        Task.Run(() => AsyncMain());

        Console.ReadLine();            
    }

    private static async void AsyncMain()
    {
        while (true)
        {
            // Imagine calling a database to get some work items to do, in this case 5 dummy items
            for (int i = 0; i < 5; i++)
            {
                var x = DoSomethingAsync(counter.ToString());

                counter++;
                Thread.Sleep(50);
            }

            Thread.Sleep(1000);
        }
    }

    private static async Task<string> DoSomethingAsync(string jobNumber)
    {
        try
        {
            // Simulated mostly IO work - some could be long running
            await Task.Delay(5000);
            Console.WriteLine(jobNumber);
        }
        catch (Exception ex)
        {
            LogException(ex);
        }

        Log("job {0} has completed", jobNumber);

        return "fire and forget so not really interested";
    }

任务.运行...

    private static int counter = 1;

    static void Main(string[] args)
    {
        Console.Title = "Task";

        while (true)
        {
            // Imagine calling a database to get some work items to do, in this case 5 dummy items
            for (int i = 0; i < 5; i++)
            {
                var x = Task.Run(() => { DoSomethingAsync(counter.ToString()); });

                counter++;
                Thread.Sleep(50);
            }

            Thread.Sleep(1000);
        }
    }

    private static string DoSomethingAsync(string jobNumber)
    {
        try
        {
            // Simulated mostly IO work - some could be long running
            Task.Delay(5000);
            Console.WriteLine(jobNumber);
        }
        catch (Exception ex)
        {
            LogException(ex);
        }

        Log("job {0} has completed", jobNumber);

        return "fire and forget so not really interested";
    }

从数据库中提取工作项,并在后台以“即发即忘”的方式并行异步处理它们

从技术上讲,你想要并发性。无论你想要异步并发 or 并行并发有待观察...

工作项将是 Web 服务调用和数据库查询。

这项工作受 I/O 限制,因此这意味着异步并发作为更自然的方法。

这些工作项的生产者将会受到一些限制,以确保采用某种衡量方法来安排工作。

的想法生产者/消费者队列这里隐含了。这是一种选择。 TPL Dataflow 提供了一些很好的生产者/消费者队列,它们是异步兼容的并且支持限制。

或者,您可以自己进行限制。对于异步代码,有一个内置的限制机制,称为SemaphoreSlim.


TPL 数据流方法,带限制:

private static int counter = 1;

static void Main(string[] args)
{
    Console.Title = "Async";
    var x = Task.Run(() => MainAsync());
    Console.ReadLine();          
}

private static async Task MainAsync()
{
  var blockOptions = new ExecutionDataflowBlockOptions
  {
    MaxDegreeOfParallelism = 7
  };
  var block = new ActionBlock<string>(DoSomethingAsync, blockOptions);
  while (true)
  {
    var dbData = await ...; // Imagine calling a database to get some work items to do, in this case 5 dummy items
    for (int i = 0; i < 5; i++)
    {
      block.Post(counter.ToString());
      counter++;
      Thread.Sleep(50);
    }
    Thread.Sleep(1000);
  }
}

private static async Task DoSomethingAsync(string jobNumber)
{
  try
  {
    // Simulated mostly IO work - some could be long running
    await Task.Delay(5000);
    Console.WriteLine(jobNumber);
  }
  catch (Exception ex)
  {
    LogException(ex);
  }
  Log("job {0} has completed", jobNumber);
}

手动限制的异步并发方法:

private static int counter = 1;
private static SemaphoreSlim semaphore = new SemaphoreSlim(7);

static void Main(string[] args)
{
    Console.Title = "Async";
    var x = Task.Run(() => MainAsync());
    Console.ReadLine();          
}

private static async Task MainAsync()
{
  while (true)
  {
    var dbData = await ...; // Imagine calling a database to get some work items to do, in this case 5 dummy items
    for (int i = 0; i < 5; i++)
    {
      var x = DoSomethingAsync(counter.ToString());
      counter++;
      Thread.Sleep(50);
    }
    Thread.Sleep(1000);
  }
}

private static async Task DoSomethingAsync(string jobNumber)
{
  await semaphore.WaitAsync();
  try
  {
    try
    {
      // Simulated mostly IO work - some could be long running
      await Task.Delay(5000);
      Console.WriteLine(jobNumber);
    }
    catch (Exception ex)
    {
      LogException(ex);
    }
    Log("job {0} has completed", jobNumber);
  }
  finally
  {
    semaphore.Release();
  }
}

最后一点,我几乎从不推荐我自己的书 http://stephencleary.com/book/就这样,但我确实认为这确实会让你受益。特别是第 8.10 节(阻塞/异步队列)、第 11.5 节(节流)和 4.4(节流数据流块)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

控制台应用程序/Windows 服务中的 Async/Await 或 Task.Run 的相关文章

随机推荐