【问题标题】:Multi-threaded loop through collection with C#使用 C# 进行集合的多线程循环
【发布时间】:2015-02-26 14:43:42
【问题描述】:

我已经看到了很多关于如何做到这一点的示例(阅读了这个网站上的很多线程),但是我很难在不锁定 UI 线程的情况下获得一些可以工作的东西> AND 允许我控制一次执行的线程数

我有这个方法,它遍历集合并调用异步方法来处理项目,但它锁定了 UI...

    async Task ProcessItems()
    {
        using (var semaphore = new SemaphoreSlim(5))
        {
            var tasks = MyCollection.Select(async (MyItem) =>
            {
                await semaphore.WaitAsync();
                try
                {
                    await ProcessItem(MyItem);
                }
                finally
                {
                    semaphore.Release();
                }
            }).ToArray();

            await Task.WhenAll(tasks);
        }
    }

“ProcessItem”方法调用另一个方法,该方法通过 Internet 调用一些 API 来上传一些文件。

这一直有效,但我无法控制一次执行多少线程...

    foreach (MyItemClass MyItem in MyCollection)
    {
        MyItemClass tmp = logItem;
        Thread thread = new Thread(() => ProcessItem(tmp));
        thread.Start();
    }

编辑:这是 ProcessItem 方法...

    public async Task<string> ProcessItem(MyItemClass MyItem)
    {
        MyItem.Status = "Transferring";

        HelperClass.UploadFileOrFolder(
            siteUrl,
            MyItem.DocumentLibrary,
            MyItem.RootFolder,
            srcRootPath,
            MyItem.SourcePath);

        MyItem.Status = "Transferred";

        return "Transferred";
    }

这里是 UploadFileorFolder 方法,它使用 SharePoint.Client.File.SaveBinaryDirect 方法将文件上传到 SharePoint...

    public static void UploadFileOrFolder(string siteUrl, string libraryName, string rootFolder, string path, string file)
    {
        ClientContext ctx = GetSPContext(siteUrl);

        using (fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: true))
        {
            Microsoft.SharePoint.Client.File.SaveBinaryDirect(ctx, targetFileUrl, fs, true);
        }
    }

【问题讨论】:

  • 如果 ProcessItems 方法锁定了 UI,那么你在 ProcessItem 方法中做错了。我怀疑它做同步工作,发布ProcessItem的代码。
  • 您可以将创建的线程保存到集合/数组/列表中,然后检查哪些线程还活着。
  • 为什么需要对线程数进行细粒度控制?几乎在所有情况下,最好让线程池或其他框架方法处理分配线程;它几乎肯定会比你更有效率。
  • 您提供的代码完全是异步的。如果它阻塞了 UI 线程,那是由于调用堆栈上该方法上方或下方的代码未显示。
  • @Fubak:阅读编译器在ProcessItem 方法上给你的警告。

标签: c# multithreading threadpool asyncfileupload


【解决方案1】:

您的ProcessItem 方法被标记为async,它返回一个Task,这表明它应该是异步的,但实际上它不是异步的。它将完全同步执行。 async 只允许在方法中使用await,实际上并没有使方法异步。您目前正在收到一个编译器警告,通知您这一事实。

如果您使用的 API 公开了一种实际异步方法来上传您尝试上传的文件,那么您应该使用该方法而不是同步版本。如果没有,那么虽然不受欢迎,但您需要使用 Task.Run(或等效项)在线程池线程中异步运行同步方法。

【讨论】:

  • 您能否添加一些示例,说明我的代码在使用 Task.Run 时的外观?
  • @Fubak 您将要在线程池中运行的方法包装在Task.Run 调用和await 中。
  • @Fubak 或删除 async 并返回任务。 however, do read this 作为警告
猜你喜欢
  • 2011-11-13
  • 2023-03-29
  • 2020-08-12
  • 2022-01-16
  • 1970-01-01
  • 1970-01-01
  • 2021-06-01
  • 2013-11-07
  • 1970-01-01
相关资源
最近更新 更多