Containers pool
Редактировал(а) Alexandr Fokin 2024/07/01 11:01
internal class PoolManager<T> : IAsyncDisposable { private readonly Func<Task<T>> _createAction; private readonly Func<Func<Task<T>>, T, ValueTask<T>> _resetAction; private readonly Func<T, ValueTask> _disposeAction; private readonly bool _canCreateNew; private readonly Channel<T> _values; #region private PoolManager( Func<Task<T>> createAction, Func<Func<Task<T>>, T, ValueTask<T>> resetAction, Func<T, ValueTask> disposeAction, int? fixedSize, IEnumerable<T>? values = null ) { _createAction = createAction; _resetAction = resetAction; _disposeAction = disposeAction; _canCreateNew = !fixedSize.HasValue; if (fixedSize.HasValue) { _canCreateNew = false; _values = Channel.CreateBounded<T>(fixedSize.Value); } else { _canCreateNew = true; _values = Channel.CreateUnbounded<T>(); } if (values != null) { foreach (var elem in values) { if (!_values.Writer.TryWrite(elem)) { throw new Exception(); } } } } public static PoolManager<T> Create( Func<Task<T>> createAction, Func<Func<Task<T>>, T, ValueTask<T>> resetAction, Func<T, ValueTask> disposeAction ) { return new PoolManager<T>( createAction, resetAction, disposeAction, fixedSize: null ); } public static async Task<PoolManager<T>> CreateFixedAsync( Func<Task<T>> createAction, Func<Func<Task<T>>, T, ValueTask<T>> resetAction, Func<T, ValueTask> disposeAction, int initCount ) { var createTasks = Enumerable.Repeat(true, initCount) .Select(e => createAction()) .ToArray(); await Task.WhenAll(createTasks); return new PoolManager<T>( createAction, resetAction, disposeAction, fixedSize: initCount, values: createTasks.Select(e => e.Result) ); } #endregion #region public async Task<PoolItem> GetAsync() { T value; if (_canCreateNew) { if (!_values.Reader.TryRead(out value!)) { value = await _createAction(); } } else { value = await _values.Reader.ReadAsync(); } return new PoolManager<T>.PoolItem( this, value ); } public async ValueTask DisposeAsync() { List<Task> disposeTasks = new List<Task>(5); while (_values.Reader.TryRead(out var elem)) { disposeTasks.Add( _disposeAction(elem).AsTask() ); } await Task.WhenAll(disposeTasks); } #endregion #region public record PoolItem : IAsyncDisposable { private readonly PoolManager<T> _poolManager; public T Value { get; } public PoolItem( PoolManager<T> poolManager, T value ) { _poolManager = poolManager; Value = value; } public async ValueTask DisposeAsync() { var value = await _poolManager._resetAction(_poolManager._createAction, Value); if (!_poolManager._values.Writer.TryWrite(value)) { throw new Exception(); } } } #endregion } | |
System. Threading. Channels | |