簡體   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