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

我的方法名()

- 有一个用于 90,000 个条目的 for 循环(以及该 for 循环内的一些验证)。

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

}

当 timer1 中的时间完成一分钟后,我想停止执行 for 循环中的其他条目。例如,如果在一分钟内完成了 45,000 个条目,我想停止执行该方法,即。一分钟后停止该方法。

然而,上面的计时器代码执行到所有 90000 条记录都在 for 循环内循环完成,不知何故该方法一分钟都没有运行?有什么帮助吗?

4

6 回答 6

3

两件事情。首先,您的计时器代码实际上并未连接到MyMethodName. 计时器被设计为在时间过去时运行进程(并且可能定期运行,具体取决于它的设置方式。

其次,要中止循环,您必须将代码放入循环中。关键是在循环之前有一个秒表或类似的开始,然后在循环开始时检查已经过去了多少时间。如果是一分钟或更长时间break;

需要注意的关键是,您不会在一分钟内完全停止,而是会在该分钟到期时完成正在运行的循环的迭代,然后停止。这通常是您想要的,因为中途停止处理可能会导致令人讨厌的副作用。

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

请注意,这Thread.Sleep是因为否则我会过快地完成所有 90000 次迭代。;-)

于 2013-07-05T19:29:43.037 回答
2

所以你可能需要一个完全不同的实现。考虑一下:

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

然后当你想运行它时:

_worker.RunWorkerAsync();

但是,您可以使其更加健壮。你可以这样打发时间:

_worker.RunWorkerAsync(60000);

然后在DoWork处理程序中,执行以下操作:

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

此外,使用BackgroundWorker,您可以支持取消。只需将WorkerSupportsCancellation标志设置为true,然后在条件下执行以下操作:

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

因此,如有必要,您可以这样做:

_worker.CancelAsync();
于 2013-07-05T19:29:50.100 回答
1

然而,上面的计时器代码执行到所有 90000 条记录都在 for 循环内循环完成,不知何故该方法一分钟都没有运行?有什么帮助吗?

在您释放 UI 线程之前,计时器不会引发事件,直到方法完全完成后才会发生。

如果您想阻止该方法运行超过特定的持续时间,您可以直接在您的方法中处理它:

MyMethodName(TimeSpan.FromMinutes(1));

然后,在您的方法中:

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

话虽如此,更好的方法是将其推送到后台线程中,并根据需要取消。

于 2013-07-05T19:31:04.763 回答
1

嗯,用秒表代替

  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;

}
于 2013-07-05T19:30:00.590 回答
0

您可以通过将事件处理程序连接到 Timer 对象中的 Tick 事件来在验证中设置一个标志以查看它是否已完成

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

你的原始代码在哪里

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

代替MyMethodName

//inside the loop
for (int i = 0; i <= 90000; i++)
{
    //validations go here
    lock(_lock)
        if(elapsed)
            break;
}
于 2013-07-05T19:32:22.653 回答
0

如果将 aCancellationTokenSourceCancellationTokenSource(TimeSpan)构造函数一起使用,则可以轻松编写在指定时间后取消操作的方法。

您可以编写如下方法:

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

然后您可以编写任何将 aCancellationToken作为参数的操作,如下所示:

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

您可以像这样使用它:

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

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

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

让我们把它放在一个完整的演示程序中:

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();
        }
    }
}
于 2013-07-05T19:54:56.700 回答