Windows服务中的并行任务

4
我有一个Windows服务,它按照计时器的设定启动一个函数。该函数查询数据库以获取新记录,并为每个找到的新记录调用Web服务。
现在有一个要求,即该服务需要在每个时间间隔内为多个数据库执行此操作。
该服务当前的形式如下:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.ServiceProcess;

namespace MiManager.TicketLogger {

  public partial class TicketLogger : ServiceBase {

    private TicketLoggerSettings _settings;
    private List<DbConnectionSettings> _connections;

    public TicketLogger() {
      InitializeComponent();
    }

    protected override void OnStart(string[] args) {

      var helpers = new MiManager.TicketLogger.Helpers();
      _settings = helpers.GetTicketLoggerSettings();
      _connections = helpers.GetDbConnectionSettings();

      if (_settings.LogVerbose == true) evlgTicketLogger.WriteEntry("Registry entries obtained", EventLogEntryType.Information, 100);
      tmrTicketLogger.Interval = _settings.ServiceInterval;
      tmrTicketLogger.Elapsed += new System.Timers.ElapsedEventHandler(TimerElapsed);
      tmrTicketLogger.Enabled = true;
      tmrTicketLogger.Start();
    }

    protected override void OnStop() {
      tmrTicketLogger.Stop();
      tmrTicketLogger.Enabled = false;
    }

    private void TimerElapsed(Object sender, System.Timers.ElapsedEventArgs e) {
      try {
        tmrTicketLogger.Stop();

        Core core = new MiManager.TicketLogger.Core();
        List<Message> messages = core.LogTickets(_settings);
        foreach (var message in messages) {
          evlgTicketLogger.WriteEntry(message.Text, message.EntryType, message.ErrorCode);
        }
        if (_settings.LogVerbose == true) {
          evlgTicketLogger.WriteEntry("Ticket logging complete", EventLogEntryType.Information, 101);
        }
      }
      catch (Exception ex) {
        evlgTicketLogger.WriteEntry(ex.ToString(), EventLogEntryType.Error, 400);
      }
      finally {
        tmrTicketLogger.Start();
      }
    }

  }

}

现在我需要调整服务以获取多个连接字符串,并在TimerElapsed函数中为每个db连接调用LogTickets函数。
在Windows服务中,目前推荐的做法是什么?
在以前的一个项目中,很多年前,我为每个要处理的连接手动创建了一个新线程,但我相信现在有更好的方法吧?
这是Async/Await的一个好用例吗?如果我这样做,Core类中的所有方法是否都必须是异步的?
使用类似Parallel.ForEach这样的东西会更好吗?

你没有展示你在哪里使用了_connections,或者记录是如何被获取的。 - Dustin Kingen
内部基于EF的存储库类有助手类从注册表获取自己的连接字符串。这将不得不更改,因为我需要检测所有必需的连接详细信息并对其进行迭代。 - Nick
2个回答

4
在服务器端,async方法可以提高可扩展性。然而,听起来您的服务不需要太多扩展,所以async实际上并没有给您带来任何优势。

那么使用类似于Parallel.ForEach会更好吗?

如果您现有的代码是同步的(并且您不需要async提供的可扩展性),那么这很好。如果您将所有内容更改为async,则您的服务将会更少占用资源(可能稍微更快)-但这需要进行相当多的代码更改,而收益却很小(AFAICS)。
如果您想在Win32服务中探索async代码,我建议使用我的AsyncContextThread类型创建单个主线程。只要您的async代码是正确异步的(例如,使用EF6进行异步DB调用HttpClient进行异步Web调用),那么您应该只需要一个线程。

谢谢你,我想我可能首先探索Parallel.ForEach路线,每个间隔它只需要处理两到三个连接,因此不需要太多的扩展。 - Nick
@Stephen,你有没有在Windows服务中使用AsyncContextThread类型的例子?我已经研究过它了,但还没有完全理解。我有一个服务,我认为可以从在不占用线程的情况下运行大量I/O密集型任务中受益匪浅。谢谢! - Todd Menier
@ToddMenier:实际上我没有。但是我有一些关于托管服务的帖子,可能会对你有所帮助(http://blog.stephencleary.com/2013/10/managed-services-roundup.html)。如果不清楚,请发布问题,大家会帮忙解答。 - Stephen Cleary
@StephenCleary 谢谢,我已经在这里发布了一个详细的问题(https://dev59.com/dWIj5IYBdhLWcg3wIx_W),希望你能参与讨论,因为你似乎是这个领域的专家! - Todd Menier

0
很多事情取决于您的解决方案的复杂性需求,您如何处理数据以及您当前的.NET框架版本,因为有许多方法可以做到这一点。
您可以像这样做,其中HandleConnection是处理连接的函数:
var parallelTask = Task.Factory.StartNew(() => Parallel.ForEach(_connections, connection => HandleConnection(connection)));

我建议花几分钟阅读一下MSDN上关于并行性、.NET 4.5中新的async/await特性以及任务的相关内容。有许多不同的任务继续选项可用。探索适合您需求的选项。 数据并行性 async和await进行异步编程 任务工厂

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接