在.NET 4中使用await SemaphoreSlim.WaitAsync

5

我的应用程序使用.NET 4。我正在使用nuget包进行await异步操作。

在我的应用程序中,我想对sempahore WaitAsync调用进行await操作,如下所示。

SemaphoreSlim semphore = new SemaphoreSlim(100);
await semphore.WaitAsync();

然而,我遇到了以下编译错误:

'System.Threading.SemaphoreSlim'不包含“WaitAsync”的定义,也没有接受类型为'System.Threading.SemaphoreSlim'的第一个参数的扩展方法“WaitAsync”可以找到(是否缺少使用指令或程序集引用?)

在.NET 4.0中有没有任何使用WaitAsync的方法?

6个回答

6

由于SemaphoreSlim.WaitAsync方法是在.Net 4.5中添加到SemaphoreSlim中的,因此您无法在.Net 4.0中使用它。

但是,您可以按照Stephen Toub在构建异步协作原语,第5部分:AsyncSemaphore中的示例实现自己的AsyncSemaphore

public class AsyncSemaphore
{
    private readonly static Task s_completed = Task.FromResult(true);
    private readonly Queue<TaskCompletionSource<bool>> m_waiters = new Queue<TaskCompletionSource<bool>>();
    private int m_currentCount; 

    public AsyncSemaphore(int initialCount)
    {
        if (initialCount < 0) throw new ArgumentOutOfRangeException("initialCount");
        m_currentCount = initialCount;
    }

    public Task WaitAsync()
    {
        lock (m_waiters)
        {
            if (m_currentCount > 0)
            {
                --m_currentCount;
                return s_completed;
            }
            else
            {
                var waiter = new TaskCompletionSource<bool>();
                m_waiters.Enqueue(waiter);
                return waiter.Task;
            }
        }
    }
    public void Release()
    {
        TaskCompletionSource<bool> toRelease = null;
        lock (m_waiters)
        {
            if (m_waiters.Count > 0)
                toRelease = m_waiters.Dequeue();
            else
                ++m_currentCount;
        }
        if (toRelease != null)
            toRelease.SetResult(true);
    }
}

2
这段代码在框架4.0中无法编译,因为Task.FromResult没有定义。我已经使用new TaskCompletionSource<bool>(true).Task替换了Task.FromResult(true)。虽然这个版本可以编译,但我还没有测试它。 - Phil Jollans
我的简单更改没有起作用。我进行了另一种更改,并将代码发布为单独的答案。 - Phil Jollans

3
正如其他人所提到的,.NET 4.5引入了SemaphoreSlim.WaitAsync。
对于.NET 4.0,您可以编写自己的异步兼容锁,或者使用我在Nito.AsyncEx NuGet包中提供的锁。您可以点击此处编写自己的锁,或者点击此处使用我的锁,该锁来自我的Nito.AsyncEx NuGet包

1
你提供的第一个链接已经失效,而第二个指向 GitHub AsyncEx 的链接不再支持 .Net 4.0。 - user12805184
1
@sodjsn26fr:Microsoft更改了第一个链接,如果你在2020年仍需要.NET 4.0,你需要使用一个旧版本的Nito.AsyncEx,它仍然可以在NuGet上找到。 - Stephen Cleary
1
@Phil Jollans,谢谢你。但是我已经尝试了“Phil Jollans”的答案并且成功了。问候。 - user12805184

2

WaitAsync是在.Net 4.5中引入的。你可以通过查看源代码自己实现扩展方法(不确定是否可行),或者使用StephenToub的AsyncSemaphore


1
作为.NET 4.0中不可用的WaitAsync,您可以使用Stephan Toub的异步同步原语系列中的代码:
public class AsyncSemaphore 
{ 
    private readonly static Task s_completed = Task.FromResult(true); 
    private readonly Queue<TaskCompletionSource<bool>> m_waiters = 
                                            new Queue<TaskCompletionSource<bool>>(); 
    private int m_currentCount; 

    public AsyncSemaphore(int initialCount)
    {
        if (initialCount < 0) 
        {
            throw new ArgumentOutOfRangeException("initialCount"); 
        }
        m_currentCount = initialCount; 
    }

    public Task WaitAsync() 
    { 
        lock (m_waiters) 
        { 
            if (m_currentCount > 0) 
            { 
                --m_currentCount; 
                return s_completed; 
            } 
            else 
            { 
                var waiter = new TaskCompletionSource<bool>(); 
                m_waiters.Enqueue(waiter); 
                return waiter.Task; 
            } 
        } 
    }

    public void Release() 
    { 
        TaskCompletionSource<bool> toRelease = null; 
        lock (m_waiters) 
        { 
            if (m_waiters.Count > 0) 
                toRelease = m_waiters.Dequeue(); 
            else 
                ++m_currentCount; 
        } 
        if (toRelease != null) 
            toRelease.SetResult(true); 
    }
}

1
不,你需要升级到.NET 4.5(或者自己编写WaitAsync扩展(或本质上是异步信号量))。 .NET 4.0的异步扩展是为了支持实际的await关键字。 .NET 4.5的大部分工作是向可以等待的各种BCL类型添加异步操作。 如果您需要这些操作,则需要升级使用的框架版本。

1

另外两个答案中提到的AysncSemaphore类,在Framework 4.0中无法编译,因为Task.FromResult未定义。

以下是我的替代版本:

public class AsyncSemaphore
{
    private readonly static Task s_completed ;
    private readonly Queue<TaskCompletionSource<bool>> m_waiters = new Queue<TaskCompletionSource<bool>>();
    private int m_currentCount; 

    static AsyncSemaphore()
    {
      var tcs = new TaskCompletionSource<bool>();
      tcs.SetResult(true);
      s_completed = tcs.Task ;
    }

    public AsyncSemaphore(int initialCount)
    {
        if (initialCount < 0) throw new ArgumentOutOfRangeException("initialCount");
        m_currentCount = initialCount;
    }

    public Task WaitAsync()
    {
        lock (m_waiters)
        {
            if (m_currentCount > 0)
            {
                --m_currentCount;
                return s_completed;
            }
            else
            {
                var waiter = new TaskCompletionSource<bool>();
                m_waiters.Enqueue(waiter);
                return waiter.Task;
            }
        }
    }
    public void Release()
    {
        TaskCompletionSource<bool> toRelease = null;
        lock (m_waiters)
        {
            if (m_waiters.Count > 0)
                toRelease = m_waiters.Dequeue();
            else
                ++m_currentCount;
        }
        if (toRelease != null)
            toRelease.SetResult(true);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接