在Application.Idle中调用DoEvents

发布于 2024-10-01 05:00:39 字数 1537 浏览 5 评论 0原文

我远离 Application.DoEvents,因为存在重入问题,而且总有另一种方法可以避免阻塞 UI。长期以来,我更喜欢在 Application.Idle 事件中执行后台工作,作为多线程的简单替代方案。但是,对于长时间运行的任务,使用 DoEvents 循环在 Application.Idle 中运行操作是否可以接受?

class LongRunningTask : IDisposable {

    public LongRunningTask(IEnumerable<Tidbit> listOfDataToBeProcessed) {
       Application.Idle += OnIdle;
    
        foreach(Tidbit t in listofDataToBeProcessed) {
            tidbits.Enqueue(t);
        }
    }
    
    // Small pieces of data to process
    Queue<Tidbit> tidbits = new Queue<Tidbit>();
    
    void OnIdle(object sender, EventArgs e) {
        while(tidbits.Count > 0) {
            var tidbit = tasks.Dequeue();
            tidbit.Process();
            // Process any messages that have queued up
            // while the data was being processed
            Application.DoEvents();
        }
    }
    
    public void Dispose() {
        Application.Idle -= OnIdle;
    }
}

这里的逻辑是,在我们调用 DoEvents 的 Application.Idle 事件中,没有排队的消息,因此我们不应该能够重新输入代码。每个花絮都会被足够快地处理,因此它不会显着占用消息队列(或 UI)。

那么,这种方法有什么坏处或缺点吗?即,在 Idle 事件中调用 DoEvents 是否安全?我确实知道 C# 5 将有一个功能来解决这种情况,但对于我们这些不使用 C# 5 的人来说(这是大多数我们现在),出于普遍的好奇心,这是一个好计划吗?或者是否有更简单的替代方案可以在长时间运行的操作期间处理消息而无需诉诸多线程?

请不要以为我想象这是一颗灵丹妙药。我知道它与任何异步方法都有相同的缺陷。我知道一个人必须仍然能够保持他的应用程序处于一致的状态。我知道知道有多线程解决方案。我正在避免那些。为什么?因为多线程比较复杂。我不认为这是不切实际的。

I stay away from Application.DoEvents, since there is the issue of re-entrancy and there is always another way to avoid holding up the UI. I've long prefered to do background work in the Application.Idle event as a simple alternative to multi-threading. But, for long-running tasks, is it acceptable to run operations in Application.Idle with a DoEvents loop?

class LongRunningTask : IDisposable {

    public LongRunningTask(IEnumerable<Tidbit> listOfDataToBeProcessed) {
       Application.Idle += OnIdle;
    
        foreach(Tidbit t in listofDataToBeProcessed) {
            tidbits.Enqueue(t);
        }
    }
    
    // Small pieces of data to process
    Queue<Tidbit> tidbits = new Queue<Tidbit>();
    
    void OnIdle(object sender, EventArgs e) {
        while(tidbits.Count > 0) {
            var tidbit = tasks.Dequeue();
            tidbit.Process();
            // Process any messages that have queued up
            // while the data was being processed
            Application.DoEvents();
        }
    }
    
    public void Dispose() {
        Application.Idle -= OnIdle;
    }
}

The logic here is that in the Application.Idle event, where we call DoEvents, there are no messages queued, so we should not be able to re-enter code. Each tidbit would be processed quickly enough that it should not hold up the message queue (or UI) significantly.

So, is there any harm or drawback to this approach? Namely, is it safe to call DoEvents in the Idle event? I do know that C# 5 will have a feature to address this sort of situation, but for those of us who aren't using C# 5 (which is most of us at the moment), and out of general curiosity, is this a good plan? Or is there a simpler alternative to process messages during a long-running operation without resorting to multi-threading?

Please don't think that I imagine this to be a magic bullet. I know that it comes with the same pitfalls as any asynchronous approach. I am aware that one must still be able to keep his application in a consistent state. And I am aware that there are multithreaded solutions. I am avoiding those. Why? Because multi-threading is more complicated. I don't think that that's impractical.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

墨落画卷 2024-10-08 05:00:39

您在这里所做的事情看起来很像协作多任务处理。这是一个有趣的想法,但我想说你真的应该使用多线程来做这样的事情。 .NET 有很多帮助系统,例如 Task.Factory.StartNew() 和 TPL 库,它们确实让这一切变得简单。

我建议不要这样做。

但需要明确的是:我没有明确的理由反对它。与许多有关编程的领域一样:如果它有效,它就有效。但是,您将不应该混合在一起的东西混合在一起,特别是后台任务和 UI 任务。我相信,当您分离后台任务并开始着手使用多线程、线程池、后台任务和 TPL 时,您很快就会发现它确实有效,并且从长远来看会让生活变得更轻松。

What you're doing here looks a lot like Cooperative multitasking. It's an interesting idea but I would say that you should really use multi threading for something like this. .NET has a lot of helper systems like Task.Factory.StartNew() and the TPL libraries that really make it easy.

I would advise against it.

To be clear though: I do not have a clear reason against it. As with a lot of areas concerning programming: if it works, it works. However, you are mixing things together that should not be mixed together, specifically background tasks and UI tasks. I believe that when you separate the background tasks and start go get your hands dirty with multi threading, thread pools, background tasks and TPL, you'll quickly see that it does work and makes life easier in the long run.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文