【问题标题】:How to run a method after a specific time interval?如何在特定时间间隔后运行方法?
【发布时间】:2014-06-23 17:04:02
【问题描述】:

很清楚:例如,想象一下我的表单中的一个按钮。当用户点击按钮时,一些 void 方法应该在 30 秒后运行。

会有一个 void 方法DoAfterDelay 接受两个输入参数。第一个是要做的方法(使用委托),另一个是时间间隔。所以我会有:

public delegate void IVoidDelegate();
static void DoAfterDelay(IVoidDelegate TheMethod, TimeSpan Interval)
    {
        // *** Some code that will pause the process for "Interval".
        TheMethod();
    }

所以,我只需要一段代码来将进程暂停特定的时间间隔。到目前为止,我使用此代码来执行此操作:

System.Threading.Thread.Sleep(Interval);

但是这段代码对我没有好处,因为它会停止整个过程并冻结程序。我不希望程序卡在DoAfterDelay 方法中。这就是Thread.Sleep 没用的原因。

那么有人可以提出更好的方法吗?当然,我已经对此进行了搜索,但我发现的大多数解决方案都是基于使用计时器(例如here)。但是使用计时器是我最后的意见,因为该方法应该运行一次并且使用计时器会使程序难以阅读。因此,如果有的话,我正在寻找更好的解决方案。或者我必须使用计时器?

我想我必须玩线程,但不确定。所以我想知道是否有人可以指导我找到解决方案。提前致谢。

【问题讨论】:

    标签: c# multithreading winforms timer


    【解决方案1】:

    你可以使用任务吗?

    Task.Factory.StartNew(() =>
    {
        System.Threading.Thread.Sleep(Interval);
        TheMethod();
    });
    
    

    【讨论】:

    • 感谢您的回答。所以实际上玩线程是解决方案。
    • @MostafaFarzán 让一个线程坐在那里什么都不做,这样你就可以在一段时间后执行一些代码,这是非常低效/浪费的。
    • 这是在用户单击按钮的情况下,因此不会产生很大的开销,因为它不会经常发生。否则我建议编写一个任务调度程序。
    • System.Threading.Tasks.Task,但仍然出现错误:跨线程操作无效:控件“panel1”从创建它的线程以外的线程访问。
    • 在任务的线程上你不能修改控件的属性。为此,您必须使用调度程序来更新 UI 线程上的属性。
    【解决方案2】:

    您可以在这里使用 .Net 4.5 的异步等待功能

    您可以使用 Task.Delay 以毫秒为单位给出延迟。 这是一种非常干净的方式。例如:

    private async void button1_Click(object sender, EventArgs e)
    {
        await Task.Delay(5000);
    
        TheMethod();
    }
    

    【讨论】:

      【解决方案3】:

      有几种创建线程的方法,当然,这取决于你在做什么。 您可以像这样动态创建线程:

      Thread aNewThread = new Thread(
          () => OnGoingFunction()
      );
      aNewThread.Start();
      

      此线程将在后台运行。您想要执行的功能应该有一个 sleep 方法在完成处理时休眠。所以是这样的:

      private void OnGoingFunction()
      {
         //Code....
         Thread.Sleep(100); //100 ms, this is in the thead so it will not stop your winForm
         //More code....
      }
      

      希望对你有帮助。

      另一种选择是在您需要处理线程时创建线程,而不必担心睡眠选项。每次只创建一个新线程来加载进程

      【讨论】:

        【解决方案4】:

        你应该创建一个Coroutine

        public IEnumerator waitAndRun()
        {
            // WAIT FOR 3 SEC
            yield return new WaitForSeconds(3);
            // RUN YOUR CODE HERE ...
        }
        

        然后调用它:

        StartCoroutine(waitAndRun());
        

        【讨论】:

          【解决方案5】:

          DoAfterDelay 启动一个只运行一次的计时器,当它到期时它会调用您的 void 'TheMethod' 函数。 为什么会这么乱?

          【讨论】:

            【解决方案6】:

            您可以使用指定确切的秒数

            DateTime runTime = new DateTime();
            double waitSeconds = (runTime - DateTime.Now).TotalSeconds;
            
            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(TimeSpan.FromSeconds(waitSeconds));
                YourMethod();
            });
            

            runTime => 当你想执行方法时。

            【讨论】:

              【解决方案7】:

              这就是你想要的:

              public static void Example1c()
              {
                  Action action = DoSomethingCool;
                  TimeSpan span = new TimeSpan(0, 0, 0, 5);
              
                  ThreadStart start = delegate { RunAfterTimespan(action, span); };
                  Thread t4 = new Thread(start);
                  t4.Start();
              
                  MessageBox.Show("Thread has been launched");
              }
              
              public static void RunAfterTimespan(Action action, TimeSpan span)
              {
                  Thread.Sleep(span);
                  action();
              }
              
              private static void DoSomethingCool()
              {
                  MessageBox.Show("I'm doing something cool");
              }
              

              使用 Action 的好处之一是可以很容易地修改它以传入参数。假设您希望能够将整数传递给 DoSomethingCool。就这样修改:

              public static void Example1c()
              {
                  Action<int> action = DoSomethingCool;
                  TimeSpan span = new TimeSpan(0, 0, 0, 5);
                  int number = 10;
              
                  ThreadStart start = delegate { RunAfterTimespan(action, span, number); };
                  Thread t4 = new Thread(start);
                  t4.Start();
              
                  MessageBox.Show("Thread has been launched");
              }
              
              public static void RunAfterTimespan(Action<int> action, TimeSpan span, int number)
              {
                  Thread.Sleep(span);
                  action(number);
              }
              
              private static void DoSomethingCool(int number)
              {
                  MessageBox.Show("I'm doing something cool");
              }
              

              非常灵活...

              【讨论】:

                【解决方案8】:

                这是一个针对Dispatcher 的简单扩展,您可以以非阻塞方式使用它。

                public static void InvokeAfter(this Dispatcher dispatcher, int milliseconds, Action delayedAction) {
                
                    Task.Factory.StartNew(() => {
                        System.Threading.Thread.Sleep(milliseconds);
                        dispatcher.Invoke(delayedAction);
                    });
                }
                

                下面是你如何使用Lambda

                SomeLabel.Dispatcher.InvokeAfter(3000, () => {
                    SomeLabel.Text = "Hello World";
                });
                

                您也可以将它与任何与Action 匹配的东西一起使用。这是一个使用本地函数的示例...

                void doLater(){
                    SomeLabel.Text = "Hello World";
                }
                
                // Pass the action itself, not the result of the action (i.e. don't use parentheses with 'doLater'.)
                SomeLabel.Dispatcher.InvokeAfter(3000, doLater);
                

                注意:然后您可以针对通常调用Invoke 的任何调度程序对象调用它。为了安全起见,我喜欢使用处理我正在更新的控件的调度程序来调用它。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2016-10-03
                  • 2011-06-04
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-03-25
                  相关资源
                  最近更新 更多