调度员调用(...)VS的BeginInvoke(...)混乱 [英] Dispatcher Invoke(...) vs BeginInvoke(...) confusion

查看:198
本文介绍了调度员调用(...)VS的BeginInvoke(...)混乱的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很困惑,为什么我不能做这个测试计数器应用工作,2(或更多)同时运行countertextboxes与伯爵()方法在我的调度使用的BeginInvoke的。

您可以通过一个调用替换BeginInvoke的解决这个问题。但是,这并没有解决我的困惑。

下面的示例code我说的是:

 公共类CounterTextBox:文本框
{
    私人诠释_number;    公共无效启动()
    {
        (新动作(计数))的BeginInvoke(NULL,NULL);
    }    私人无效计数()
    {
        而(真)
        {
            如果(_number ++盐10000)_number = 0;
            this.Dispatcher.BeginInvoke(新动作(UPDATETEXT),System.Windows.Threading.DispatcherPriority.Background,NULL);
        }
    }    私人无效UPDATETEXT()
    {
        this.Text =+ _number;
    }
}


解决方案

当您使用 Dispatcher.BeginInvoke 这意味着它的日程表的给定在UI线程执行的动作在稍后的时间点,然后返回控制以允许当前线程继续执行。 调用阻塞调用者,直到预定的动作完成。

当您使用的BeginInvoke 你的循环将要运行的超级快,因为的BeginInvoke 返回的时候了。行动到消息队列,这意味着您要添加的很多的和的地段的。您要添加他们的的速度比他们实际上可以被处理。这意味着,有当您计划消息之间很长一段时间,当它真正得到一个机会来运行。

这是你正在运行的实际操作使用的字段 _number 。但 _number 正在被其他线程的非常迅速的改性的而行动是在队列的。这意味着它不会显示 _number 在你预定操作的时间的价值,而是它是什么之后,它已经在它被持续上是非常紧密的循环。

如果您使用 Dispatcher.Invoke ,而不是那么prevents从走在前面的自己,并有多个计划的事件循环,从而保证值它的写作始终是当前值。此外,通过强制循环的每次迭代等待消息来运行它使环少了很多紧,所以它不能在一般作为快速运行

如果你想使用的BeginInvoke 你真正需要做的第一件事是你的循环减慢。如果你想它来更新文本每一秒,或曾经10ms或什么的,那么你可以使用 Thread.sleep代码来等待的时间适量。

接下来,你需要将它传递给调度,使其显示之前采取 _number 的副本在您安排它的时间价值,而不是在一次执行:

 ,而(真)
{
    如果(_number ++盐10000)
        _number = 0;
    INT副本= _number;
    this.Dispatcher.BeginInvoke(新动作(()=> UPDATETEXT(复印件))
        ,System.Windows.Threading.DispatcherPriority.Background,NULL);
    Thread.sleep代码(200);
}


 私人无效UPDATETEXT(INT数)
{
    this.Text = number.ToString();
}

I'm confused why I can't make this test counter application work with 2 (or more) simultaneous running countertextboxes with the use of "BeginInvoke" on my Dispatcher in the Count() method.

You can solve the issue by replacing the BeginInvoke by an Invoke. But this doesn't solve my confusion.

Here's the sample code I'm talking about:

public class CounterTextBox : TextBox
{
    private int _number;

    public void Start()
    {
        (new Action(Count)).BeginInvoke(null, null);
    }

    private void Count()
    {
        while (true)
        {
            if (_number++ > 10000) _number = 0;
            this.Dispatcher.BeginInvoke(new Action(UpdateText), System.Windows.Threading.DispatcherPriority.Background, null);    
        }
    }

    private void UpdateText()
    {
        this.Text = "" + _number;
    }
}

解决方案

When you use Dispatcher.BeginInvoke it means that it schedules the given action for execution in the UI thread at a later point in time, and then returns control to allow the current thread to continue executing. Invoke blocks the caller until the scheduled action finishes.

When you use BeginInvoke your loop is going to run super fast since BeginInvoke returns right away. This means that you're adding lot and lots of actions to the message queue. You're adding them much faster than they can actually be processed. This means that there's a long time between when you schedule a message and when it actually gets a chance to be run.

The actual action that you're running uses the field _number. But _number is being modified by the other thread very quickly and while the action is in the queue. This means that it won't display the value of _number at the time you scheduled the action, but rather what it is after it has been continuing on in it's very tight loop.

If you use Dispatcher.Invoke instead then it prevents the loop from "getting ahead of itself" and having multiple scheduled events, which ensures that the value that it's writing is always the "current" value. Additionally, by forcing each iteration of the loop to wait for the message to be run it makes the loop a lot less "tight", so it can't run as quickly in general.

If you want to use BeginInvoke the first thing you really need to do is slow down your loop. If you want it to update the text every second, or ever 10ms, or whatever, then you can use Thread.Sleep to wait the appropriate amount of time.

Next, you need to take a copy of _number before passing it to the Dispatcher so that it displays the value at the time you scheduled it, not at the time it is executed:

while (true)
{
    if (_number++ > 10000)
        _number = 0;
    int copy = _number;
    this.Dispatcher.BeginInvoke(new Action(() => UpdateText(copy))
        , System.Windows.Threading.DispatcherPriority.Background, null);
    Thread.Sleep(200);
}


private void UpdateText(int number)
{
    this.Text = number.ToString();
}

这篇关于调度员调用(...)VS的BeginInvoke(...)混乱的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆