【问题标题】:Semaphore wrapper method信号量包装方法
【发布时间】:2017-10-06 17:51:07
【问题描述】:

基于一些关于SO的问题,主要是这个: Throttling asynchronous tasks

我已经实现了 SemaphoreSlim 对象,以便通过我的应用程序中的一系列方法同时处理请求。这些方法中的大多数都在获取 ID 列表,并以并发方式从 Web 获取每个 ID 的单字节数组。实现如下所示:

 using (var semaphore = new SemaphoreSlim(MaxConcurrency))
                {
                    var tasks = fileMetadata.GroupBy(x => x.StorageType).Select(async storageTypeFileMetadata=>
                    {
                        await semaphore.WaitAsync();
                        try
                        {
                            var fileManager = FileManagerFactory.CreateFileManager((StorageType)storageTypeFileMetadata.Key);
                            await fileManager.UpdateFilesAsync(storageTypeFileMetadata);
                        }
                        finally
                        {
                            semaphore.Release();
                        }
                    });

                    await Task.WhenAll(tasks);
                }

有没有办法为信号量代码抽象出一个方法或者一些可重用的代码sn-p,把我需要做的工作传进去,这样就可以重复使用而无需每次都重新编写信号量代码?使用相同信号量模式的多个方法之间的唯一区别是我正在迭代的列表以及它在 try{} 中所做的工作。

我正在考虑类似将 list.select(x=> my task method with my work in it) 传递给一个信号量方法,该方法是所有包装信号量代码。

【问题讨论】:

  • 因此,为了在开发时节省一些击键,您愿意在运行时进行委托实例化和调用。是这样吗?
  • 主要原因首先是出于好奇,其次是不可能有 20 多个方法包含在完全相同的代码中,这使得可读性变得更加困难,因为该方法的主要功能是 2 行。跨度>

标签: c# async-await task semaphore


【解决方案1】:

所以我猜是这样的:

public static class Extension
{
    public static async Task ExecuteAsync<T>(this IEnumerable<T> items, Func<T, Task> task, int concurrency)
    {
        var tasks = new List<Task>();

        using (var semaphore = new SemaphoreSlim(concurrency))
        {
            foreach (var item in items)
            {
                tasks.Add(ExecuteInSemaphore(semaphore, task, item));
            }

            await Task.WhenAll(tasks);
        }
    }

    private static async Task ExecuteInSemaphore<T>(SemaphoreSlim semaphore, Func<T, Task> task, T item)
    {
        await semaphore.WaitAsync();

        try
        {
            await task(item);
        }
        finally
        {
            semaphore.Release();
        }
    }
}

然后你会像这样使用它:

await fileMetadata.GroupBy(x => x.StorageType).ExecuteAsync(storageTypeFileMetadata =>
{
    var fileManager = FileManagerFactory.CreateFileManager((StorageType)storageTypeFileMetadata.Key);
    return fileManager.UpdateFilesAsync(storageTypeFileMetadata);
}, 4);

【讨论】:

  • 仍在测试,但看起来需要在 lambda 之前添加异步 .ExecuteAsync(async storageTypeFileMetadata =>
  • @mameesh 仅当您等待其中的某些内容时。在我给出的示例中,这不是必需的
猜你喜欢
  • 2017-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-24
  • 1970-01-01
  • 2020-02-01
相关资源
最近更新 更多