Run and stop a method for a minute

徘徊边缘 提交于 2021-01-27 07:22:41

问题


timer1= new System.Windows.Forms.Timer();
timer1.Interval =60000; // 1 min
timer1.Start();
MyMethodName();
timer1.Stop();

MyMethodName()

-has a for loop for 90,000 entries (and some validations inside that for loop).

for (int i = 0; i <= 90000; i++)
{
 //validations go here

}

When the time in timer1 is done for a minute, i want to stop executing other entries in the for loop. For example, if 45,000 entries are done in a minute, i want to stop executing the method ie. stop the method after a minute.

However the above timer code, executes till all the 90000 records are done looping inside the for loop, somehow the method doesn't run for a minute? Any help?


回答1:


Two things. Firstly Your timer code is not actually connected to the running of MyMethodName. A timer is designed to run processes when the time has elapsed (and possibly at regular intervals depending on how it is set up.

Secondly and more to the point of your question to abort a loop you have to put code inside the loop. The key would be to have a stopwatch or similar start before your loop and then at the beginning of your loop check how much time has elapsed. If it is a minute or more then break;.

The key thing to note is that you will not stop exactly on a minute but you will finish the iteration of the loop that is running when the minute expires and then stop. This is usually what you want since stopping processing midway through something may cause nasty side effects.

Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i =0; i<=90000; i++)
{
    if (stopwatch.Elapsed>TimeSpan.FromSeconds(5))
        break;
    Console.WriteLine(i);
    Thread.Sleep(1000);
}

Note that Thread.Sleep is there just because otherwise I get through all 90000 iterations too quickly. ;-)




回答2:


So you would likely need a much different implementation. Consider this:

public class MyForm
{
    private BackgroundWorker _worker;

    public MyForm()
    {
        _worker = new BackgroundWorker();
        _worker.DoWork += (s, args) =>
        {
            var timer = Stopwatch().StartNew();
            do
            {
                // do something
            } while (timer.ElapsedMilliseconds < 60000)
        };
    }
}

and then when you want to run it:

_worker.RunWorkerAsync();

However, you could make it even more robust. You could pass the time in like this:

_worker.RunWorkerAsync(60000);

and then in the DoWork handler, do this:

while (timer.ElapsedMilliseconds < (int)args.Argument)

Further, with the BackgroundWorker, you could support cancellation. Just set the WorkerSupportsCancellation flag to true and then in the condition do this:

while (timer.ElapsedMilliseconds < (int)args.Argument && !_worker.CancellationPending)

so, if necessary, you could do this:

_worker.CancelAsync();



回答3:


Hmm, use a stopwatch instead

  Stopwatch stopWatch = new Stopwatch();
    stopWatch.Start();


for(int i= 0; i <= 90000; i++)
{
    // Get the elapsed time as a TimeSpan value.
    TimeSpan ts = stopWatch.Elapsed;

if(ts.Seconds >= 60)
  break;

}



回答4:


However the above timer code, executes till all the 90000 records are done looping inside the for loop, somehow the method doesn't run for a minute? Any help?

The timer will not raise events until you free up the UI thread, which won't occur until after the method completes fully.

If you want to prevent the method from running past a specific duration, you could handle it in your method directly:

MyMethodName(TimeSpan.FromMinutes(1));

Then, in your method:

void MyMethodName(TimeSpan maxRuntime)
{
    DateTime expiration = DateTime.Now + maxRuntime;

    for (int i = 0; i <= 90000; i++)
    {
         //validations go here

         if (i % 100 == 0) //  check every 100?
         {
              if (DateTime.Now > expiration) 
                    break;
         }
    }
}

That being said, a better approach would be to push this into a background thread, and cancel as needed.




回答5:


you can set a flag on in validations to see if it is done or not by hooking up an event handler to the Tick event in the Timer object

//in an area accessible to 
//both elements
object readonly _lock = new object();
bool elapsed = false;

where your original code was

elapsed = false;
timer1= new System.Windows.Forms.Timer();
timer1.Interval =60000; // 1 min
timer1.Tick=((sender, everntArgs)=>
{
    lock(_lock)
        elapsed = true; 
});
timer1.Start();
MyMethodName();
timer1.Stop();

Inside of MyMethodName

//inside the loop
for (int i = 0; i <= 90000; i++)
{
    //validations go here
    lock(_lock)
        if(elapsed)
            break;
}



回答6:


If you use a CancellationTokenSource with the CancellationTokenSource(TimeSpan) constructor, it makes it easy to write a method that will cancel an action after a specified time.

You can write a method like so:

public static void RunTimedAction(Action<CancellationToken> action, TimeSpan timeout)
{
    using (var cancellationTokenSource = new CancellationTokenSource(timeout))
        action(cancellationTokenSource.Token);
}

And then you can write any action that takes a CancellationToken as a parameter, like this:

private void action(CancellationToken cancel)
{
    int i;

    for (i = 0; i < 1000000; ++i)
    {
        if (cancel.IsCancellationRequested)
            break;

        Thread.Sleep(10); // Simulate work.
    }

    Console.WriteLine("action() reached " + i);
}

Which you can use like this:

Console.WriteLine("Started at " + DateTime.Now);

RunTimedAction(action, TimeSpan.FromSeconds(10));

Console.WriteLine("Stopped at " + DateTime.Now);

Let's put this together into a complete demo program:

using System;
using System.Threading;

namespace Demo
{
    class Program
    {
        void run()
        {
            Console.WriteLine("Started at " + DateTime.Now);

            RunTimedAction(action, TimeSpan.FromSeconds(10));

            Console.WriteLine("Stopped at " + DateTime.Now);
        }

        private void action(CancellationToken cancel)
        {
            int i;

            for (i = 0; i < 1000000; ++i)
            {
                if (cancel.IsCancellationRequested)
                    break;

                Thread.Sleep(10); // Simulate work.
            }

            Console.WriteLine("action() reached " + i);
        }

        public static void RunTimedAction(Action<CancellationToken> action, TimeSpan timeout)
        {
            using (var cancellationTokenSource = new CancellationTokenSource(timeout))
                action(cancellationTokenSource.Token);
        }

        static void Main()
        {
            new Program().run();
        }
    }
}


来源:https://stackoverflow.com/questions/17495622/run-and-stop-a-method-for-a-minute

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!