什么将是一个有效的方法,在异步enviromment共享资源池?将是、共享资源、有效、方法

2023-09-07 08:48:11 作者:待我强大给父母一个天下

想象一下几个任务试图用一个资源池兼任。从池中的单个资源仅可用于通过在时间的任务的一个特定号码;的数量可以是一个。

Imagine several tasks trying to use a pool of resources concurrently. A single resource from the pool can only be used by an specific number of tasks at time; the number can be one.

在同步的环境中,在我看来, WaitHandle.WaitAny &放大器; 旗语 是要走的路。

In a synchronous environment, it seems to me that WaitHandle.WaitAny & Semaphore is the way to go.

var resources = new[] { new Resource(...), new Resource(...) }; // 'Resource' custom class wrapers the resource
var semaphores = new[] { new Semaphore(1, 1), new Semaphore(1, 1) };
... 
var index = WaitHandle.WaitAny(semaphores);

try
{
    UseResource(resources[index]);
}
finally
{
    semaphores[index].Release();
}

但是,我们应该做什么在异步环境中?

But what should we do in an asynchronous environment?

推荐答案

我一般建议开发商从用的逻辑分离池的逻辑。这种分离的一个不错的附带好处是,只有池逻辑需要同步。

I generally recommend that developers separate the "pooling" logic from the "using" logic. One nice side benefit of that separation is that only the pooling logic requires synchronization.

在实际的情况中的资源将被运行时已知的数目;更多precisely这将是在应用程序(即配置)的初始化。

In the real scenario the number of resources would be run-time known; more precisely it would be at the initialization of the application (i.e. configuration).

在服务器上的每个端口只接受一个客户在时间和每个服务器只提供一个端口。

Each port on the server accepts only one client at time and each server has only one port available.

所以,你有一个有限的资源集,并且每个资源只能在一个时间被用于一个线程

So, you have a finite set of resources, and each resource can only be used by one thread at a time.

既然你不能按需创建新的资源,你需要一个信号,要知道当一个人可用。你可以自己做,或者你可以使用的东西就像一个 BufferBlock< T> 来充当异步就绪队列

Since you can't create new resources on-demand, you'll need a signal to know when one is available. You can do this yourself, or you can use something like a BufferBlock<T> to act as an async-ready queue.

由于每个资源只能在同一时间内使用一个线程,我建议使用常见的的IDisposable 技术释放资源回池中。

Since each resource can only be used by one thread at a time, I recommend using the common IDisposable technique for freeing the resource back to the pool.

把这些在一起:

public sealed class Pool
{
  private readonly BufferBlock<Resource> _block = new BufferBlock<Resource>();

  public Pool()
  {
    _block.Post(new Resource(this, ...));
    _block.Post(new Resource(this, ...));
  }

  public Resource Allocate()
  {
    return _block.Receive();
  }

  public Task<Resource> AllocateAsync()
  {
    return _block.ReceiveAsync();
  }

  private void Release(Resource resource)
  {
    _block.Post(resource);
  }

  public sealed class Resource : IDisposable
  {
    private readonly Pool _pool;
    public Resource(Pool pool, ...)
    {
      _pool = pool;
      ...
    }

    public void Dispose()
    {
      _pool.Release(this);
    }
  }
}

用法:

using (var resource = Pool.Allocate())
    UseResource(resource);

using (var resource = await Pool.AllocateAsync())
    await UseResourceAsync(resource);