Call function at each time interval efficiently

3

I have a question, I'm making a game server and I need a specific function to be run every 10 seconds.

I know that Thread.Sleep() exists (in combination with while(true) ), but it does not seem to be a good option

I've heard of Timers (tried to use, but for some reason it only calls the first time and then to) and Windows Services .

How do I make a function call every time interval efficiently?

    
asked by anonymous 01.09.2016 / 18:25

4 answers

6

You can also do with Reactive Extensions , asynchronous based on events.

Add the package via nuget

  

Install-Package System.Reactive

var observable = Observable
    .Interval(TimeSpan.FromSeconds(10))
        //.Do((x) => { }) // log events 
    ;

//primeiro subscriber
observable.Subscribe((x) =>
{
    Console.WriteLine($"multiplica {x} x 2 = {x * 2}");
});

//segundo subscriber
observable.Subscribe((x) =>
{
    Console.WriteLine($"potência {x}^2 = {Math.Pow(x, 2)}");
});

In this way several actions will be able to respond ( subscribers ) to this event generator, in my opinion it leaves the code better structured.

    
02.09.2016 / 03:23
5

Using timers

  

Generate an event after a defined interval in order to generate events   recurring.

Use Timer as follows:

public class Servidor
{
public static System.Timers.Timer _timer;
public static void Main()
{

    _timer = new System.Timers.Timer();
    _timer.AutoReset = false;
    _timer.Interval = 1000; // Intervalo em milésimos
    _timer.Elapsed += new System.Timers.ElapsedEventHandler(executarTarefa);
    _timer.Enabled = true;
}

static void executarTarefa(object sender, System.Timers.ElapsedEventArgs e)
{
    _timer.Enabled = false;
    // Seu código
    _timer.Enabled = true;
}

Do not forget the property AutoReset because if it is as true , it will only execute once, as described in your question.

    
02.09.2016 / 14:29
0

I understand you're open to options, so here's one more:

TopShelf

It creates a very simple environment for creating Windows Services with timers.

Just install TopShelf NuGet Package in your Console Application project:

  

Install-Package Topshelf

Then, in a very elegant way, create your service:

public class Program
{
    public static void Main(string[] args)
    {
        HostFactory.Run(configurator =>
        {
            configurator.Service<MeuServicoPeriodico>(s =>
            {
                s.ConstructUsing(name => new MeuServicoPeriodico());
                s.WhenStarted((service, control) => service.Start(control));
                s.WhenStopped((service, control) => service.Stop(control));
            });
            configurator.RunAsLocalSystem();
            configurator.SetDescription("Sobre meu serviço periódico");
        });
    }
}

Next, create the container that will trigger and control the life cycle of your service:

public sealed class MeuServicoPeriodico: ServiceControl
{
    private readonly CancellationTokenSource _cancellationTokenSource;

    public MeuServicoPeriodico()
    {
        _cancellationTokenSource = new CancellationTokenSource();
    }

    public bool Start(HostControl hostControl)
    {
        Task.Run(() =>
        {
            while (true)
            {
                // Funções do seu aplicativo vão aqui

                Thread.Sleep(TimeSpan.FromSeconds(5));
            }
        }, _cancellationTokenSource.Token);

        return true;
    }

    public bool Stop(HostControl hostControl)
    {
        _cancellationTokenSource.Cancel();
        _cancellationTokenSource.Dispose();
        return true;
    }
}

Yes, it uses the "concept" of while-true-sleep , but this loop is in a task where your service has full control over its lifecycle. You can pause, stop, and restart from the Windows services panel - or from anywhere else you can manage service.

See more details in this article on creating Windows Service with TopShelf .

Official site TopShelf .

    
02.09.2016 / 15:19
-2

I've already used Timers, for me it worked, here's an example code:

Timer timer = new Timer();
timer.Interval = 1000; //1000 milésimos = 1 segundo
timer.Enabled = true;
timer.Elapsed += new ElapsedEventHandler(Time_Elapsed);

Now it's just you create the Event Handler and put inside it what you want:

private void Time_Elapsed(object sender, ElapsedEventArgs e)
{
    //Alguma coisa
}

Note: Remember to put using System.Timers;

    
02.09.2016 / 09:48