【问题标题】:Timed semaphore定时信号量
【发布时间】:2014-08-10 06:48:23
【问题描述】:

我有以下类来管理对资源的访问:

class Sync : IDisposable
{
    private static readonly SemaphoreSlim Semaphore = new SemaphoreSlim(20);

    private Sync()
    {
    }

    public static async Task<Sync> Acquire()
    {
        await Semaphore.WaitAsync();
        return new Sync();
    }

    public void Dispose()
    {
        Semaphore.Release();
    }
}

用法:

using (await Sync.Acquire())
{
    // use a resource here
}

现在它允许不超过 20 次共享使用。

如何修改该类以允许每单位时间不超过 N 次共享使用(例如,每秒不超过 20 次)?

【问题讨论】:

  • 你能Acquire 然后在不同的线程中使用资源吗?如果是这样 - 您可以让主线程等待固定的时间,然后释放信号量。只是一个想法
  • 也许这可以提供一个想法:stackoverflow.com/questions/18771524/…

标签: c# .net synchronization semaphore


【解决方案1】:

“每秒 20 个”与“一次 20 个”完全不同。我建议您将线程同步抛在脑后,并使用能够更自然地以时间作为概念工作的更高级别的抽象。

特别是,Reactive Extensions 有许多不同的限制运算符。

【讨论】:

  • Observable.Throttle 会丢失请求。你可以试试Observable.CombineLatest(requestObservable, Observable.Timer(TimeSpan.FromMiliseconds(100)), (x, _) =&gt; x).Subscribe(DoSomething)
【解决方案2】:

这是一个基本的重新实现,它在指定的时间段已过时调用Semaphore.Release,或者在处置Sync 实例时(可选-参见Dispose() 中的代码cmets)

class Sync : IDisposable
{
    private static readonly SemaphoreSlim Semaphore = new SemaphoreSlim(20);

    // 0 : semaphore needs to be released.
    // 1 : semaphore already released.
    private int State = 0;

    private Sync()
    {
    }

    // Renamed to conform to Microsoft's guidelines.
    public static async Task<Sync> AcquireAsync(TimeSpan releaseAfter)
    {
        var sync = new Sync();

        await Semaphore.WaitAsync().ConfigureAwait(false);

        try
        {
            return sync;
        }
        finally
        {
            // Fire-and-forget, not awaited.
            sync.DelayedRelease(releaseAfter);
        }
    }

    private async void DelayedRelease(TimeSpan releaseAfter)
    {
        await Task.Delay(releaseAfter).ConfigureAwait(false);

        this.ReleaseOnce();
    }

    private void ReleaseOnce()
    {
        // Ensure that we call Semaphore.Release() at most
        // once during the lifetime of this instance -
        // either via DelayedRelease, or via Dispose.
        if (Interlocked.Exchange(ref this.State, 1) == 0)
        {
            Semaphore.Release();
        }
    }

    public void Dispose()
    {
        // Uncomment if you want the ability to
        // release the semaphore via Dispose
        // thus bypassing the throttling.

        //this.ReleaseOnce();
    }
}

【讨论】:

    猜你喜欢
    • 2018-11-02
    • 1970-01-01
    • 2010-10-07
    • 2017-08-24
    • 2014-12-06
    • 1970-01-01
    • 2013-11-07
    • 1970-01-01
    • 2020-02-16
    相关资源
    最近更新 更多