是否有这样的同步工具,"单项大小异步任务缓冲液QUOT ;? [英] Is there such a synchronization tool as "single-item-sized async task buffer"?

查看:112
本文介绍了是否有这样的同步工具,"单项大小异步任务缓冲液QUOT ;?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在UI开发我处理这样的方式,当一个事件首次出现的事件很多时候 - 我马上开始处理,但如果有正在进行一个处理操作 - 我等待它完成之前,我处理另一事件。如果在操作完成之前发生多个事件 - 我只处理最近的一次

Many times in UI development I handle events in such a way that when an event first comes - I immediately start processing, but if there is one processing operation in progress - I wait for it to complete before I process another event. If more than one event occurs before the operation completes - I only process the most recent one.

我通常做我的工艺方法有一个循环,并在我的事件处理程序,我检查一个字段,表示如果我目前正在处理的东西,如果我的方式 - 我把我的当前事件的参数在另一个领域,基本上是一一个项目大小的缓冲区和当前处理传球完成时 - 我检查是否有一些其他的事件来处理,我循环,直到我做了

The way I typically do that my process method has a loop and in my event handler I check a field that indicates if I am currently processing something and if I am - I put my current event arguments in another field that is basically a one item sized buffer and when current processing pass completes - I check if there is some other event to process and I loop until I am done.

现在这似乎有点太重复,可能不是最优雅的方式来做到这一点,但它似乎为我工作,否则罚款。我有两个问题,则:

Now this seems a bit too repetitive and possibly not the most elegant way to do it, though it seems to otherwise work fine for me. I have two questions then:


  1. 做什么,我需要做的有名字吗?

  2. 有一些可重复使用的同步类型,在那里,可以为我做的?

我想加的东西由Stephen Toub我的包括在我的工具箱

I'm thinking of adding something to the set of async coordination primitives by Stephen Toub that I included in my toolkit.

推荐答案

因此​​,首先,我们会处理,你描述了其中的方法始终是从UI线程,或其他一些同步的情况下使用的情况。在运行方法本身可异步来处理所有通过同步上下文封送我们。

So first, we'll handle the case that you described in which the method is always used from the UI thread, or some other synchronization context. The Run method can itself be async to handle all of the marshaling through the synchronization context for us.

如果我们运行我们刚刚设置的下一个存储的动作。如果我们不能,那么我们表明,我们现在运行,等待操作,然后继续等待下一个动作,直到没有下一个动作。我们确保无论何时我们完成了我们表明,我们完成了运行:

If we're running we just set the next stored action. If we're not, then we indicate that we're now running, await the action, and then continue to await the next action until there is no next action. We ensure that whenever we're done we indicate that we're done running:

public class EventThrottler
{
    private Func<Task> next = null;
    private bool isRunning = false;

    public async void Run(Func<Task> action)
    {
        if (isRunning)
            next = action;
        else
        {
            isRunning = true;
            try
            {
                await action();
                while (next != null)
                {
                    var nextCopy = next;
                    next = null;
                    await nextCopy();
                }
            }
            finally
            {
                isRunning = false;
            }
        }
    }

    private static Lazy<EventThrottler> defaultInstance =
        new Lazy<EventThrottler>(() => new EventThrottler());
    public static EventThrottler Default
    {
        get { return defaultInstance.Value; }
    }
}

由于该类是,至少一般,将是完全从UI线程使用的有一般将需要只有一个,所以我加了一个默认实例的便利性,但由于它仍可能有意义有要多于一个在一个程序,我没有做它一个单身。

Because the class is, at least generally, going to be used exclusively from the UI thread there will generally need to be only one, so I added a convenience property of a default instance, but since it may still make sense for there to be more than one in a program, I didn't make it a singleton.

运行接受 Func键&LT;任务&GT; 的想法,则通常是一个异步的lambda。它看起来像:

Run accepts a Func<Task> with the idea that it would generally be an async lambda. It might look like:

public class Foo
{
    public void SomeEventHandler(object sender, EventArgs args)
    {
        EventThrottler.Default.Run(async () =>
        {
            await Task.Delay(1000);
            //do other stuff
        });
    }
}

好了,所以,刚需冗长,这里是处理该事件处理程序是从不同的线程调用的情况下一个版本。我知道你说,你认为他们都从UI线程调用,但我全身有点。这意味着锁定了所有访问在锁定块类型的实例字段,但不实际执行在锁定块。这最后一部分是重要的不只是性能,保证我们不只是从设置接下来现场封锁的项目,同时也避免与行动还呼吁运行的问题,所以,它不需要处理重入的问题或潜在死锁。这种模式在锁块做的东西,然后的,回应基于锁确定的条件是指设置局部变量来表示锁定期结束后应做什么。

Okay, so, just to be verbose, here is a version that handles the case where the event handlers are called from different threads. I know you said that you assume they're all called from the UI thread, but I generalized it a bit. This means locking over all access to instance fields of the type in a lock block, but not actually executing the function inside of a lock block. That last part is important not just for performance, to ensure we're not blocking items from just setting the next field, but also to avoid issues with that action also calling run, so that it doesn't need to deal with re-entrancy issues or potential deadlocks. This pattern, of doing stuff in a lock block and then responding based on conditions determined in the lock means setting local variables to indicate what should be done after the lock ends.

public class EventThrottlerMultiThreaded
{
    private object key = new object();
    private Func<Task> next = null;
    private bool isRunning = false;

    public void Run(Func<Task> action)
    {
        bool shouldStartRunning = false;
        lock (key)
        {
            if (isRunning)
                next = action;
            else
            {
                isRunning = true;
                shouldStartRunning = true;
            }
        }

        Action<Task> continuation = null;
        continuation = task =>
        {
            Func<Task> nextCopy = null;
            lock (key)
            {
                if (next != null)
                {
                    nextCopy = next;
                    next = null;
                }
                else
                {
                    isRunning = false;
                }
            }
            if (nextCopy != null)
                nextCopy().ContinueWith(continuation);
        };
        if (shouldStartRunning)
            action().ContinueWith(continuation);
    }
}

这篇关于是否有这样的同步工具,&QUOT;单项大小异步任务缓冲液QUOT ;?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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