Programing

C #에서 매일 특정 시간에 메서드를 호출하는 방법은 무엇입니까?

crosscheck 2020. 10. 30. 07:43
반응형

C #에서 매일 특정 시간에 메서드를 호출하는 방법은 무엇입니까?


나는 SO를 검색하고 Quartz.net에 대한 답변을 찾았습니다. 하지만 내 프로젝트에는 너무 큰 것 같습니다. 동등한 솔루션을 원하지만 더 간단하고 코드 내에서 (외부 라이브러리가 필요하지 않음). 매일 특정 시간에 메소드를 호출하려면 어떻게해야합니까?

이에 대한 몇 가지 정보를 추가해야합니다.

  • 이 작업을 수행하는 가장 간단하고 추악한 방법은 매초 / 분마다 시간을 확인하고 적절한 시간에 메서드를 호출하는 것입니다.

나는 이것을하기위한보다 효과적인 방법을 원하고, 시간을 지속적으로 확인할 필요가 없으며, 작업이 완료되지 않았는지 여부를 제어 할 수 있습니다. 방법이 실패하면 (문제로 인해), 프로그램은 로그 쓰기 / 이메일 보내기를 알아야합니다. 그래서 작업을 예약하는 것이 아니라 메서드를 호출해야합니다.

이 솔루션을 찾았 습니다 Java 의 Java 에서 고정 시간에 메서드 호출 . C #에도 비슷한 방법이 있습니까?

편집 : 나는 이것을했다. void Main ()에 매개 변수를 추가하고이 매개 변수로 프로그램을 실행하기 위해 bat (Windows 작업 스케줄러에 의해 예약 됨)를 만들었습니다. 프로그램이 실행되고 작업을 수행 한 다음 종료됩니다. 작업이 실패하면 로그를 작성하고 이메일을 보낼 수 있습니다. 이 접근 방식은 내 요구 사항에 잘 맞습니다. :)


  • 원하는 작업을 수행하는 콘솔 앱 만들기
  • Windows " 예약 된 작업 "기능을 사용하여 실행에 필요한 시간에 해당 콘솔 앱을 실행하도록합니다.

그게 정말 필요한 전부입니다!

업데이트 : 앱 내에서이 작업을 수행하려면 몇 가지 옵션이 있습니다.

  • A의 윈도우 폼의 응용 프로그램, 당신은 활용할 수있는 Application.Idle이벤트와 당신의 메소드를 호출 할 수있는 일의 시간에 도달했는지 확인하십시오. 이 메서드는 앱이 다른 작업으로 바쁘지 않을 때만 호출됩니다. 목표 시간에 도달했는지 확인하는 빠른 확인은 앱에 너무 많은 스트레스를주지 않아야한다고 생각합니다.
  • ASP.NET 웹앱에는 예약 된 이벤트를 "시뮬레이션"하는 방법이 있습니다.이 CodeProject 기사를 확인 하십시오.
  • 물론 모든 .NET 앱에서 "자신 만의 롤링"을 수행 할 수도 있습니다 . 샘플 구현은 CodeProject 기사참조하십시오.

업데이트 # 2 : 60 분마다 확인하려면 60 분마다 깨어나는 타이머를 만들고 시간이 다되면 메서드를 호출합니다.

이 같은:

using System.Timers;

const double interval60Minutes = 60 * 60 * 1000; // milliseconds to one hour

Timer checkForTime = new Timer(interval60Minutes);
checkForTime.Elapsed += new ElapsedEventHandler(checkForTime_Elapsed);
checkForTime.Enabled = true;

그런 다음 이벤트 처리기에서 :

void checkForTime_Elapsed(object sender, ElapsedEventArgs e)
{
    if (timeIsReady())
    {
       SendEmail();
    }
}

이러한 기능이 필요한 응용 프로그램을 빌드 할 때마다 찾은 간단한 .NET 라이브러리통해 항상 Windows 작업 스케줄러를 사용합니다 .

제발 비슷한 질문에 대한 내 대답을 참조 일부 샘플 코드 등을 설명합니다.


사용하기 쉽고 외부 라이브러리를 사용할 필요가없는 간단한 스케줄러를 만들었습니다. TaskScheduler는 타이머에 대한 참조를 유지하는 싱글 톤이므로 타이머가 가비지 수집되지 않고 여러 작업을 예약 할 수 있습니다. 스케줄링시이 시간이 초과되면 첫 번째 실행 (시간 및 분)을 설정할 수 있습니다.이 시간이 다음날 스케줄링 시작됩니다. 그러나 코드를 사용자 지정하는 것은 쉽습니다.

새 작업을 예약하는 것은 매우 간단합니다. 예 : 11:52에 첫 번째 작업은 15 초마다, 두 번째 예는 5 초마다입니다. 매일 실행하려면 24를 3 매개 변수로 설정하십시오.

TaskScheduler.Instance.ScheduleTask(11, 52, 0.00417, 
    () => 
    {
        Debug.WriteLine("task1: " + DateTime.Now);
        //here write the code that you want to schedule
    });

TaskScheduler.Instance.ScheduleTask(11, 52, 0.00139,
    () =>
    {
        Debug.WriteLine("task2: " + DateTime.Now);
        //here write the code that you want to schedule
    });

내 디버그 창 :

task2: 07.06.2017 11:52:00
task1: 07.06.2017 11:52:00
task2: 07.06.2017 11:52:05
task2: 07.06.2017 11:52:10
task1: 07.06.2017 11:52:15
task2: 07.06.2017 11:52:15
task2: 07.06.2017 11:52:20
task2: 07.06.2017 11:52:25
...

프로젝트에이 클래스를 추가하기 만하면됩니다.

public class TaskScheduler
{
    private static TaskScheduler _instance;
    private List<Timer> timers = new List<Timer>();

    private TaskScheduler() { }

    public static TaskScheduler Instance => _instance ?? (_instance = new TaskScheduler());

    public void ScheduleTask(int hour, int min, double intervalInHour, Action task)
    {
        DateTime now = DateTime.Now;
        DateTime firstRun = new DateTime(now.Year, now.Month, now.Day, hour, min, 0, 0);
        if (now > firstRun)
        {
            firstRun = firstRun.AddDays(1);
        }

        TimeSpan timeToGo = firstRun - now;
        if (timeToGo <= TimeSpan.Zero)
        {
            timeToGo = TimeSpan.Zero;
        }

        var timer = new Timer(x =>
        {
            task.Invoke();
        }, null, timeToGo, TimeSpan.FromHours(intervalInHour));

        timers.Add(timer);
    }
}

다른 사람들이 말했듯이 콘솔 앱을 사용하여 예정된 시간에 실행할 수 있습니다. 다른 사람들이 말하지 않은 것은이 앱이 메인 ​​애플리케이션에서 기다리고있는 크로스 프로세스 EventWaitHandle을 트리거 할 수 있다는 것입니다.

콘솔 앱 :

class Program
{
    static void Main(string[] args)
    {
        EventWaitHandle handle = 
            new EventWaitHandle(true, EventResetMode.ManualReset, "GoodMutexName");
        handle.Set();
    }
}

주요 앱 :

private void Form1_Load(object sender, EventArgs e)
{
    // Background thread, will die with application
    ThreadPool.QueueUserWorkItem((dumby) => EmailWait());
}

private void EmailWait()
{
    EventWaitHandle handle = 
        new EventWaitHandle(false, EventResetMode.ManualReset, "GoodMutexName");

    while (true)
    {
        handle.WaitOne();

        SendEmail();

        handle.Reset();
    }
}

내가 알고있는 가장 간단한 방법은 Windows 작업 스케줄러를 사용하여 특정 시간에 코드를 실행하거나 응용 프로그램을 영구적으로 실행하고 특정 시간을 확인하거나 작업을 수행하는 Windows 서비스를 작성하는 것입니다. 같은.


나는 이것이 오래되었다는 것을 알고 있지만 이것은 어떻습니까?

다음 실행 시간까지의 시간을 계산하는 시작시 실행할 타이머를 빌드하십시오. 런타임을 처음 호출 할 때 첫 번째 타이머를 취소하고 새로운 일일 타이머를 시작합니다. 매일 또는 원하는 주기로 변경하십시오.


다음은 TPL을 사용하여이를 수행하는 방법입니다. 타이머 등을 생성 / 삭제할 필요가 없습니다.

void ScheduleSomething()
{

    var runAt = DateTime.Today + TimeSpan.FromHours(16);

    if (runAt <= DateTime.Now)
    {
        DoSomething();
    }
    else
    {
        var delay = runAt - DateTime.Now;
        System.Threading.Tasks.Task.Delay(delay).ContinueWith(_ => DoSomething());
    }

}

void DoSomething()
{
    // do somethig
}

실행 파일을 실행하려면 Windows 예약 된 작업을 사용하십시오. 나는 당신이 현재 프로그램에서 실행될 메소드를 원한다고 (아마도 잘못된 것으로) 가정 할 것입니다.

메소드가 호출 된 마지막 날짜를 저장하는 스레드를 계속 실행하지 않는 이유는 무엇입니까?

예를 들어 1 분마다 깨우고 현재 시간이 지정된 시간보다 크고 저장된 마지막 날짜가 현재 날짜가 아닌 경우 메서드를 호출 한 다음 날짜를 업데이트합니다.


나일 수도 있지만 대부분의 답변이 완전하지 않거나 제대로 작동하지 않는 것 같습니다. 나는 아주 빠르고 더러운 것을 만들었습니다. 이런 식으로하는 것이 얼마나 좋은 아이디어인지는 확실하지 않지만 매번 완벽하게 작동합니다.

while (true)
{
    if(DateTime.Now.ToString("HH:mm") == "22:00")
    {
        //do something here
        //ExecuteFunctionTask();
        //Make sure it doesn't execute twice by pausing 61 seconds. So that the time is past 2200 to 2201
        Thread.Sleep(61000);
    }

    Thread.Sleep(10000);
}

최근에 매일 다시 시작해야하는 ac # 앱을 작성했습니다. 이 질문이 오래되었다는 것을 알고 있지만 다른 가능한 해결책을 추가하는 것이 아프다고 생각하지 않습니다. 이것이 내가 지정된 시간에 매일 다시 시작하는 방법입니다.

public void RestartApp()
{
  AppRestart = AppRestart.AddHours(5);
  AppRestart = AppRestart.AddMinutes(30);
  DateTime current = DateTime.Now;
  if (current > AppRestart) { AppRestart = AppRestart.AddDays(1); }

  TimeSpan UntilRestart = AppRestart - current;
  int MSUntilRestart = Convert.ToInt32(UntilRestart.TotalMilliseconds);

  tmrRestart.Interval = MSUntilRestart;
  tmrRestart.Elapsed += tmrRestart_Elapsed;
  tmrRestart.Start();
}

타이머가 범위 내에 있는지 확인하려면 메서드를 사용하여 System.Timers.Timer tmrRestart = new System.Timers.Timer()메서드 외부에서 만드는 것이 좋습니다 . RestartApp()양식로드 이벤트에 메소드 넣으십시오 . 응용 프로그램이 시작되면 AppRestartif current이 다시 시작 시간보다 큰 경우 1 일을 추가하여 다시 시작이 정시에 AppRestart발생하고 타이머에 음수 값을 넣는 예외가 발생하지 않도록합니다. 에서 tmrRestart_Elapsed어떤 코드 이벤트 실행하면 특정 시간에 실행 된이 필요합니다. 응용 프로그램이 자체적으로 다시 시작되는 경우 반드시 타이머를 중지 할 필요는 없지만 문제가되지는 않습니다. 응용 프로그램이 다시 시작되지 않으면 RestartApp()메서드를 다시 호출 하면됩니다.


매 60 분마다 실행할 시간을 설정하는 대신 남은 시간을 계산하고 타이머를 절반 (또는 다른 부분)으로 설정할 수 있습니다. 이렇게하면 시간을 많이 확인하지 않고 타이머 간격이 목표 시간에 가까워 질수록 정확도를 유지합니다.

예를 들어 지금부터 60 분 동안 무언가를하려는 경우 타이머 간격은 거의 다음과 같습니다.

30:00:00, 15:00:00, 07:30:00, 03:45:00, ..., 00:00:01, RUN!

아래 코드를 사용하여 하루에 한 번 서비스를 자동으로 다시 시작합니다. 나는 타이머가 오랜 기간 동안 신뢰할 수 없다는 것을 알았 기 때문에 스레드를 사용하지만이 예제에서는 더 많은 비용이 들지만이 목적을 위해 만들어진 유일한 것이므로 중요하지 않습니다.

(VB.NET에서 변환)

autoRestartThread = new System.Threading.Thread(autoRestartThreadRun);
autoRestartThread.Start();

...

private void autoRestartThreadRun()
{
    try {
        DateTime nextRestart = DateAndTime.Today.Add(CurrentSettings.AutoRestartTime);
        if (nextRestart < DateAndTime.Now) {
            nextRestart = nextRestart.AddDays(1);
        }

        while (true) {
            if (nextRestart < DateAndTime.Now) {
                LogInfo("Auto Restarting Service");
                Process p = new Process();
                p.StartInfo.FileName = "cmd.exe";
                p.StartInfo.Arguments = string.Format("/C net stop {0} && net start {0}", "\"My Service Name\"");
                p.StartInfo.LoadUserProfile = false;
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                p.StartInfo.CreateNoWindow = true;
                p.Start();
            } else {
                dynamic sleepMs = Convert.ToInt32(Math.Max(1000, nextRestart.Subtract(DateAndTime.Now).TotalMilliseconds / 2));
                System.Threading.Thread.Sleep(sleepMs);
            }
        }
    } catch (ThreadAbortException taex) {
    } catch (Exception ex) {
        LogError(ex);
    }
}

참고 최소 간격을 1000ms로 설정했습니다.이 간격은 필요한 정확도에 따라 증가, 감소 또는 제거 될 수 있습니다.

응용 프로그램이 닫힐 때 스레드 / 타이머도 중지해야합니다.


이에 대한 간단한 접근 방식이 있습니다. 이렇게하면 작업이 발생하기 전에 1 분 지연됩니다. Thread.Sleep (); 만들기 위해 초를 추가 할 수도 있습니다. 짧아.

private void DoSomething(int aHour, int aMinute)
{
    bool running = true;
    while (running)
    {
        Thread.Sleep(1);
        if (DateTime.Now.Hour == aHour && DateTime.Now.Minute == aMinute)
        {
            Thread.Sleep(60 * 1000); //Wait a minute to make the if-statement false
            //Do Stuff
        }
    }
}

24 시간

var DailyTime = "16:59:00";
            var timeParts = DailyTime.Split(new char[1] { ':' });

            var dateNow = DateTime.Now;
            var date = new DateTime(dateNow.Year, dateNow.Month, dateNow.Day,
                       int.Parse(timeParts[0]), int.Parse(timeParts[1]), int.Parse(timeParts[2]));
            TimeSpan ts;
            if (date > dateNow)
                ts = date - dateNow;
            else
            {
                date = date.AddDays(1);
                ts = date - dateNow;
            }

            //waits certan time and run the code
            Task.Delay(ts).ContinueWith((x) => OnTimer());

public void OnTimer()
    {
        ViewBag.ErrorMessage = "EROOROOROROOROR";
    }

나는 이것이 매우 유용하다는 것을 알았습니다.

using System;
using System.Timers;

namespace ScheduleTimer
{
    class Program
    {
        static Timer timer;

        static void Main(string[] args)
        {
            schedule_Timer();
            Console.ReadLine();
        }

        static void schedule_Timer()
        {
            Console.WriteLine("### Timer Started ###");

            DateTime nowTime = DateTime.Now;
            DateTime scheduledTime = new DateTime(nowTime.Year, nowTime.Month, nowTime.Day, 8, 42, 0, 0); //Specify your scheduled time HH,MM,SS [8am and 42 minutes]
            if (nowTime > scheduledTime)
            {
                scheduledTime = scheduledTime.AddDays(1);
            }

            double tickTime = (double)(scheduledTime - DateTime.Now).TotalMilliseconds;
            timer = new Timer(tickTime);
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.Start();
        }

        static void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            Console.WriteLine("### Timer Stopped ### \n");
            timer.Stop();
            Console.WriteLine("### Scheduled Task Started ### \n\n");
            Console.WriteLine("Hello World!!! - Performing scheduled task\n");
            Console.WriteLine("### Task Finished ### \n\n");
            schedule_Timer();
        }
    }
}

참고 URL : https://stackoverflow.com/questions/3243348/how-to-call-a-method-daily-at-specific-time-in-c

반응형