【问题标题】:How to wait for a resource using await / async如何使用 await / async 等待资源
【发布时间】:2014-08-26 21:20:23
【问题描述】:

我不完全理解所有 .Net 异步编程概念(等待、异步、等待者、同步上下文等)如何工作。

我正在使用套接字,它们需要缓冲区来进行读/写操作,我希望有一个 BufferAllocator 对象来搜索和返回缓冲区以供套接字使用。关键是当没有足够的可用内存(缓冲区池为空)时,应用程序应等待缓冲区并在所需的可用内存量可用时继续。

我该如何实现呢?

好的,这是我的作业(为了简单起见只是一个演示,它不是我的真实代码):

class Program
{
    private static BufferAllocator _allocator;

    static void Main(string[] args)
    {
        _allocator = new BufferAllocator(100);   // 100 bytes
        Task.Factory.StartNew(async () =>
        {
            await _allocator.GetBufferAsync(40); // 100 - 40 = 60bytes
            await _allocator.GetBufferAsync(40); //  60 - 40 = 20bytes 
            await _allocator.GetBufferAsync(40); //  20 < 40 (wait)
            Console.WriteLine("Worked!");  // <-------+
        }); //                                        |
        Console.ReadKey(); //                         |
        _allocator.ReleaseBuffer(40); // after pessing a key, release 40 bytes
        Console.ReadKey();
    }

}

class BufferAllocator
{
    private int _availableBytes;
    private SemaphoreSlim _signal = new SemaphoreSlim(0, 1);

    public BufferAllocator(int bufferSize)
    {
        _availableBytes = bufferSize;
    }

    public async Task GetBufferAsync(int size)
    {
        while(_availableBytes < size)
            await _signal.WaitAsync();

        _availableBytes -= size;
    }

    public void ReleaseBuffer(int size)
    {
        _availableBytes += size;
        _signal.Release();
    }
}

注意:会有多个套接字并行读写。请给我一个线索。

【问题讨论】:

    标签: c# .net asynchronous task-parallel-library async-await


    【解决方案1】:

    当您自己实际实现async 构造时,您可能应该使用TaskCompletionSource。将其视为一个信号对象。它有一个Task 属性,您可以将其异步返回给您的客户await。然后您使用TaskCompletionSource 的方法(例如SetResult)更新任务的状态。这就是一方(生产者)“通知”另一方(该特定任务的消费者)应该恢复的方式。

    您当然可以使用适合的内置构造,​​例如基于大小的SemaphoreSlim,或AsyncAutoResetEvent

    确保您永远不会忘记完成您的任务(结果,例外或取消)。否则你将面临最令人不快的错误/死锁。

    【讨论】:

    • 我创建了一个 tcs 并返回它的 Taks 属性,所以当调用 SetResult 时,消费者会收到通知,我明白了。我不知道在哪里调用 SetResult 方法。我的意思是,当我的 ReleaseBuffer 方法被调用时,它应该验证是否有可用内存,对吗?如果是,并且 GetBufferAsync 方法可能会被多次调用,我在哪里共享请求的大小值?
    • 我很难想象他会如何在这里使用TaskCompletionSource。为他的事业等待内部结构还不够吗?
    • @lontivero @YuvalItzchakov 当您没有要返回的缓冲区并且希望调用者等待时,您会返回一个任务。当您确实有要返回的缓冲区时结束该任务,因此您使用缓冲区“唤醒”调用者。这可能是当有人返回缓冲区时,或者当您决定创建更多时。如果缓冲区的数量始终相同,则可以使用SemaphoreSlim。如果是动态的,则需要直接使用TaskCompletionSource
    猜你喜欢
    • 1970-01-01
    • 2019-08-14
    • 2021-06-15
    • 2012-09-23
    • 2021-12-11
    • 2016-03-08
    • 1970-01-01
    • 1970-01-01
    • 2022-11-07
    相关资源
    最近更新 更多