当 CPU 不受“SemaphoreSlim.WaitAsync”使用的影响时,有哪些替代方案?

Ant*_*kov 1 c# multithreading semaphore async-await

我有一个程序正在执行长时间运行的任务,该程序应该在程序启动时启动,并且应该可以在此后的任何时刻重新启动。

我的目的是,如果调用“重新启动”,则会发生以下情况:

  • 要求完成所有任务
  • 等待所有任务完成
  • 所有功能重新启动

我想使用 async/await 并仍然锁定启动所有任务的过程,以确保在上一个启动/重新启动完成之前不会进行任何重新启动。

正如我所看到的,由于多种原因,async/await 不适用于锁定状态,因此我最终使用了 SemaphoreSlim,它对我来说非常有用。这是我的代码:

private readonly SemaphoreSlim m_semaphoreSlim;
private CancellationTokenSource m_cancellationTokenSource;
private CancellationToken m_cancellationToken;

public FeedClientService(IList<IFeedConfigurationBuilder> feedConfigs)
{
    m_semaphoreSlim = new SemaphoreSlim(1, 1);
    m_feedConfigs = feedConfigs;
}

public void Start()
{
    Task.Run(() => this.FetchFeeds());
}

public void Restart()
{
    if (m_cancellationTokenSource != null) m_cancellationTokenSource.Cancel();

    Task.Run(() => this.FetchFeeds());
}

private async Task FetchFeeds()
{
    try
    {
        await m_semaphoreSlim.WaitAsync();

        m_cancellationTokenSource = new CancellationTokenSource();
        m_cancellationToken = m_cancellationTokenSource.Token;

        Task[] tasks = new Task[m_feedConfigs.Count];
        for (int i = 0; i < m_feedConfigs.Count; i++)
        {
            var index = i;
            tasks[index] = Task.Run(async () => await this.FetchFeed(index), m_cancellationToken);
        }

        await Task.WhenAll(tasks);
    }
    finally
    {
        m_semaphoreSlim.Release();
    }          
}
Run Code Online (Sandbox Code Playgroud)

正如此处指出的/sf/answers/290816851/ - “SemaphoreSlim 类代表一个轻量级、快速的信号量,可用于在等待时间预计非常短的情况下在单个进程中等待”。我还没有找到任何指定“非常短”的来源,并且我不确定我的代码是否不会出现性能瓶颈,因为我正在启动的任务肯定不是短期运行的任务。

TL;博士;

  • “等待时间非常短”是什么意思?
  • 如果等待时间很长,有哪些替代方案?

Ant*_*kov 5

事实证明,SemaphoreSlim.WaitAsync根本没有使用旋转等待技术(仅供参考 - SemaphoreSlim 的实现)。因此,锁定资源,即使其中有长时间运行的任务,也不会影响 CPU 消耗。