繁体   English   中英

如何最好地防止在完成之前再次运行异步方法?

[英]How to best prevent running async method again before it completes?

我有这种模式,以防止在之前有机会完成之前调用异步方法。

我的解决方案涉及需要一个标志,然后需要锁定旗帜,感觉非常冗长。 有没有更自然的方法来实现这一目标?

public class MyClass
{
    private object SyncIsFooRunning = new object();
    private bool IsFooRunning { get; set;}

    public async Task FooAsync()
    {
        try
        {
            lock(SyncIsFooRunning)
            {
                if(IsFooRunning)
                    return;

                IsFooRunning = true;
            }

            // Use a semaphore to enforce maximum number of Tasks which are able to run concurrently.
            var semaphoreSlim = new SemaphoreSlim(5);
            var trackedTasks = new List<Task>();

            for(int i = 0; i < 100; i++)
            {
                await semaphoreSlim.WaitAsync();

                trackedTasks.Add(Task.Run(() =>
                {
                    // DoTask();
                    semaphoreSlim.Release();
                }));
            }

            // Using await makes try/catch/finally possible.
            await Task.WhenAll(trackedTasks);
        }
        finally
        {
            lock(SyncIsFooRunning)
            {
                IsFooRunning = false;
            }
        }
    }
}

如评论中所述,如果您愿意,可以使用Interlocked.CompareExchange()

public class MyClass
{
    private int _flag;

    public async Task FooAsync()
    {
        try
        {
            if (Interlocked.CompareExchange(ref _flag, 1, 0) == 1)
            {
                return;
            }

            // do stuff
        }
        finally
        {
            Interlocked.Exchange(ref _flag, 0);
        }
    }
}

那就是说,我觉得这太过分了。 在这种情况下使用lock没有任何问题,特别是如果你不希望在方法上引起很多争用。 确实认为倒不如说是来包装方法,使主叫方可以一直await的结果,新的异步操作是否启动与否:

public class MyClass
{
    private readonly object _lock = new object();
    private Task _task;

    public Task FooAsync()
    {
            lock (_lock)
            {
                return _task != null ? _task : (_task = FooAsyncImpl());
            }
    }

    public async Task FooAsyncImpl()
    {
        try
        {
            // do async stuff
        }
        finally
        {
            lock (_lock) _task = null;
        }
    }
}

最后,在评论中,你这样说:

似乎有点奇怪,所有返回类型仍然对任务有效?

我不清楚你的意思是什么。 在您的方法中,唯一有效的返回类型将是voidTask 如果您的return语句返回实际值,则必须使用Task<T> ,其中T是return语句返回的类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM