等待一段时间不阻塞主线程

Posted

技术标签:

【中文标题】等待一段时间不阻塞主线程【英文标题】:Wait for a while without blocking main thread 【发布时间】:2012-01-19 17:50:10 【问题描述】:

我希望我的方法等待大约 500 毫秒,然后检查某些标志是否已更改。如何在不阻塞我的应用程序的其余部分的情况下完成此操作?

【问题讨论】:

这个问题被严重低估了;我们需要知道“应用程序的其余部分”是什么——它是否运行在同一个线程、不同的线程、不同的机器上,什么?也就是说,到目前为止,几乎所有的答案都是危险的。使用 DoEvents 或 Thread.Sleep 是最糟糕的做法,表明设计糟糕的应用程序存在严重的重入错误的危险。 Tudor 的答案是最好的:使用计时器。 另外,考虑研究 C# 5 的异步 CTP 版本。我们添加了控制流,让您可以轻松延迟 500 毫秒并从中断处继续,而不会阻塞任何线程或启动新线程消息循环。 【参考方案1】:

如果有问题的方法在与应用程序的其余部分不同的线程上执行,则执行以下操作:

Thread.Sleep(500);

【讨论】:

@user898569 根据定义,如果您想“等待某事”,则需要坐在那里“等待”。所以不,你必须使用另一个线程,否则它会阻塞你的程序。请参阅Tudor's answer 了解触发将在主线程上运行但不会“等待”的事件的方法,它只是一个周期性事件。 有趣的问题。我建议您阅读 .NET 中的异步编程。这是一个良好起点的链接:msdn.microsoft.com/en-us/vstudio/gg316360【参考方案2】:
System.Threading.Thread.Sleep(500);

更新

这不会阻塞应用程序的其余部分,只会阻塞运行方法的线程。

【讨论】:

大声笑,我的输入时间超过 7 秒,因为我放入了命名空间。不是第一个:(【参考方案3】:

我不太明白这个问题。

如果你想在检查之前阻止,请使用Thread.Sleep(500);

如果您想每 x 秒异步检查一次,您可以使用 Timer 每 x 毫秒执行一次处理程序。

这不会阻塞你当前的线程。

【讨论】:

我认为这是 OP 需要的。 如果它是一个 GUI 应用程序,那么最好使用特定于所用 GUI 库的计时器(例如,在 WPF 的情况下为DispatcherTimer)。 “每 x 秒检查一次”和“等待 x 秒然后检查”是有区别的。我相信 OP 想要后者。【参考方案4】:

Thread.Sleep(500) 将强制当前线程等待 500 毫秒。它可以工作,但如果您的整个应用程序在一个线程上运行,这不是您想要的。

在这种情况下,您需要使用Timer,如下所示:

using System.Timers;

void Main()

    Timer t = new Timer();
    t.Interval = 500; // In milliseconds
    t.AutoReset = false; // Stops it from repeating
    t.Elapsed += new ElapsedEventHandler(TimerElapsed);
    t.Start();


void TimerElapsed(object sender, ElapsedEventArgs e)

    Console.WriteLine("Hello, world!");

如果您希望计时器自动重复,您可以将 AutoReset 设置为 true(或根本不设置)。

【讨论】:

稍微修正一下,Intervalproperty 的值以 毫秒 为单位,而不是秒 link 当前线程非常有帮助。我错误地认为Thread.Sleep 导致主线程休眠。 我认为您可以向后使用 AutoReset。将其设置为 true 或根本不设置它会使计时器重复自身。 link @JochemKempe 已修复,但我不确定您为什么一年多前没有这样做。留下这条评论是为了避免让未来的 Google 员工感到困惑。【参考方案5】:

使用计时器应该可以解决问题

如果您需要使用线程,那么这里是一个示例

void Main()

    System.Threading.Thread check= new System.Threading.Thread(CheckMethod);
    check.Start();


private void CheckMethod()

     //Code
     Thread.Sleep(500);

【讨论】:

【参考方案6】:

异步任务:

 var task = new Task (() => function_test()); task.Start();

public void function_test()  `Wait for 5000 miliseconds`   Task.Delay(5000);` 

【讨论】:

【参考方案7】:

您可以使用await Task.Delay(500); 而不会像Sleep 那样阻塞线程,而且代码比定时器少得多。

【讨论】:

这需要 .NET 4.5,但如果你必须使用 .NET 4.0,你可以使用类似 ***.com/a/17717159/5815327 的东西。【参考方案8】:

我最近一直在努力解决同样的问题,即我需要在不阻塞 UI 的情况下按计划运行操作。

这是我的解决方案:

private void Button_Click(object sender, RoutedEventArgs e)

    RunOnSchedule(interval, cancellationToken);


private void RunOnSchedule(int interval, CancellationToken cancellationToken)

    // Start the task you want to run on schedule
    TaskToRunOnSchedule(args);
    Task.Run(async () => 
    
        // This loop checks if the task was requested to be cancelled every 1000 ms
        for (int x = 0; x < interval; x+=1000)
        
            if (cancellationToken.IsCancellationRequested)
            
                break;
            

            await Task.Delay(1000);
        
    ).GetAwaiter().OnCompleted(() =>
    
        // Once the task for delaying is completed, check once more if cancellation is requested, as you will reach this point regardless of if it was cancelled or not.
        if (!cancellationToken.IsCancellationRequested)
        
            // Run this method again
            RunOnSchedule(interval, cancellationToken);
        
    );

【讨论】:

【参考方案9】:

在一个 WinForms 应用程序中,当我想在主线程上等待而不阻塞应用程序时,我通常使用

private void Wait (double milliseconds)

    DateTime next = System.DateTime.Now.AddMilliseconds(milliseconds);
    while (next > System.DateTime.Now)
        Application.DoEvents();

【讨论】:

以上是关于等待一段时间不阻塞主线程的主要内容,如果未能解决你的问题,请参考以下文章

java界面子线程界面阻塞了主线程界面怎么解决?

Android主线程阻塞WebView线程

.NET - 阻塞主线程,直到有任何可用线程

面试官:如何让主线程等待所有的子线程结束之后再执行?我懵了

如何实现java主线程等待子线程执行完毕之后再执行

本机调用阻塞主线程