简体   繁体   English

Windows服务中的并行任务

[英]Parallel Tasks In Windows Services

I have a Windows Service which kicks off a function on a timer. 我有一个Windows服务,它启动计时器上的功能。 The function queries a database for new records and then calls a web service for each new record it finds. 该函数在数据库中查询新记录,然后为找到的每个新记录调用Web服务。

There is now a requirement that this service does this for multiple databases at each interval. 现在要求此服务在每个间隔为多个数据库执行此操作。

The service currently looks like this: 该服务目前看起来像这样:

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();
      }
    }

  }

}

Now I need to adjust the service to fetch multiple connection strings and call the LogTickets function in the TimerElapsed function for each db connection. 现在我需要调整服务以获取多个连接字符串,并在每个数据库连接的TimerElapsed函数中调用LogTickets函数。

What is the current recommended way of doing this in a Windows Service? 目前推荐的在Windows服务中执行此操作的方法是什么?

In a previous project many years ago I manually created a new thread for each connection I wanted to process but I'm sure there's a better way now? 在多年前的一个项目中,我手动为我想要处理的每个连接创建了一个新线程,但我相信现在有更好的方法吗?

Is it a good use case for Async/Await? 它是Async / Await的一个很好的用例吗? If I do that do all the methods in the Core class have to be async as well? 如果我这样做,Core类中的所有方法都必须是异步的吗?

Would it be better to use something like Parallel.ForEach? 使用Parallel.ForEach这样的东西会更好吗?

On the server side, async methods give you scalability. 在服务器端, async方法为您提供可伸缩性。 However, it sounds like your service doesn't need to scale much, so async wouldn't really give you any advantage. 但是,听起来您的服务不需要扩展太多,因此async不会给您带来任何好处。

Would it be better to use something like Parallel.ForEach? 使用Parallel.ForEach这样的东西会更好吗?

If your existing code is synchronous (and you don't need the scalability that async would give you), then that's fine. 如果您现有的代码是同步的(并且您不需要async会给您的可伸缩性),那就没关系。 Your service would be less resource-intensive (and probably slightly faster) if you change everything to async - but that would require quite a bit of code changes for (AFAICS) little benefit. 如果将所有内容更改为async ,那么您的服务将会消耗更少的资源(并且可能会稍微快一些) - 但这需要对(AFAICS)进行相当多的代码更改,但收效甚微。

If you do want to explore async code in a Win32 service, I recommend creating a single main thread using my AsyncContextThread type . 如果你想在Win32服务中探索async代码,我建议使用我的AsyncContextThread类型创建一个主线程。 As long as your async code is properly asynchronous (eg, using EF6 for asynchronous DB calls and HttpClient for asynchronous web calls ), then you should only need the one thread. 只要您的async代码正确异步(例如,使用EF6进行异步数据库调用 ,使用HttpClient进行异步Web调用 ),那么您应该只需要一个线程。

Much depends on the sophistication needs of your solution, how you want to handle your data and what is your current .NET framework version because there are many ways to do this. 这在很大程度上取决于您的解决方案的复杂性需求,您希望如何处理数据以及您当前的.NET框架版本是什么,因为有很多方法可以做到这一点。

You can do something like this where HandleConnection is your function for handling the connection: 您可以执行以下操作:HandleConnection是您处理连接的函数:

var parallelTask = Task.Factory.StartNew(() => Parallel.ForEach(_connections, connection => HandleConnection(connection)));

I would recommend using a few minutes to read up on parallelism, new async/await features in .NET 4.5 and tasks on MSDN. 我建议使用几分钟来阅读并行性,.NET 4.5中的新异步/等待功能以及MSDN上的任务。 There are many different continuation options that can be used with tasks. 有许多不同的延续选项可用于任务。 Explore what suits your needs. 探索适合您需求的产品。

Data Parallelism 数据并行

Asynchronous Programming with Async and Await 使用Async和Await进行异步编程

Task Factories 任务工厂

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM