簡體   English   中英

異步任務的 SemaphoreSlim 問題

[英]SemaphoreSlim problems with async tasks

我一直在嘗試使用 SemaphoreSlim 來限制我在任何時候運行的並發任務的數量,但它似乎沒有效果,可能取決於我的實現,這就是我來這里的原因。 我的 SemaphoreSlim 代碼是這樣的:

首先它被稱為

await Task.Run(() => mc.StartAsync());

調用此方法

public async Task StartAsync()
{
    using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(5))
    {
        foreach (var task in ThreadHandler.ThreadList)
        {
            await concurrencySemaphore.WaitAsync();
            try
            {
                await Task.Run(() => task.Operation.Start());
            }
            finally
            {
                concurrencySemaphore.Release();
            }
        }
    }
}

這反過來從一個看起來像這樣的列表開始一個任務,這是一個自定義的 model,之前存儲和創建了任務

public Task Operation { get; set; }
var t = new Task(async () =>
{
    await Task.Run(() => Method(input, sps));
});

記住我的代碼沒有像我預期的那樣工作,這是開始這樣的事情的正確方法嗎? 我不認為從一個點啟動 3 個任務是個好主意。 像這樣的主要原因是因為我正在執行一個Action<>並且找不到單獨等待它的方法。 這些任務是否計入SemaphoreSlim限制?

經過各種測試,我可以確認我的SemaphoreSlim代碼只是在連續執行任務,我在任務列表中添加了一個大的任務延遲,看看我是否可以阻止它執行,但新任務仍在啟動……這是什么我不見了?

如果不清楚的話,我的目標是限制並發運行的任務數量。 感謝您的幫助!

編輯:我想我已經意識到我只是在等待任務的開始,而不是完成。

我想我已經意識到我只是在等待任務的開始,而不是完成。

確實,這就是問題的核心。

您根本不應該為任何事情使用Task構造函數 就當它不存在吧。 它總是會把你引向一條尷尬的道路。

如果您有要在稍后執行的操作,您應該使用委托: ActionFunc<T>用於同步工作, Func<Task>Func<Task<T>>用於異步工作 例如,如果Method是同步的,那么您將擁有:

public Action Operation { get; set; }
...
Operation = () => Method(input, sps);

然后你可以使用Task.Run調用它:

public async Task ProcessAsync()
{
    using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(5))
    {
        var tasks = ThreadHandler.ThreadList.Select(async task =>
        {
            await concurrencySemaphore.WaitAsync();
            try
            {
                await Task.Run(() => task.Operation());
            }
            finally
            {
                concurrencySemaphore.Release();
            }
        }).ToList();
        await Task.WhenAll(tasks);
    }
}

如果OperationAction (同步)或Func<Task> (異步),上述代碼將正常工作。

但是,如果它是Action (即同步),那么您真正在做的是並行處理,而不是異步並發,並且內置類型可以幫助實現這一點:

public void Process()
{
    // Only valid if Operation is Action, not Func<Task>!
    Parallel.ForEach(
        ThreadHandler.ThreadList,
        new ParallelOptions { MaxDegreeOfParallelism = 5 },
        task => task.Operation());
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM