使用 LimitedConcurrencyLevelTask​​Scheduler 时延续任务挂起

2024-03-30

我正在研究在 C# (.NET 4.0) 中使用 TPL。

我创建了一个自定义 API 来简化 Web 请求的创建和下载内容(异步,使用延续任务)。那部分工作正常。

当我尝试使用时出现的问题LimitedConcurrencyLevelTaskScheduler(发现于并行编程示例 http://code.msdn.microsoft.com/ParExtSamples并在任务的 MSDN 文档 http://msdn.microsoft.com/en-us/library/ee789351.aspx)与延迟任务创建。如果您不熟悉该类,它所做的只是将计划的任务的并发度限制为任意数量。

基本上我想将 Web 请求任务链的创建推迟到由LimitedConcurrencyLevelTaskScheduler这样我就可以限制并发下载的数量。

正如圣人斯蒂芬·托布(Stephen Toub)所建议的那样 http://social.msdn.microsoft.com/Forums/en/parallelextensions/thread/ce2bc75d-4135-4f54-b4e1-0237062b255b,当推迟创建Task,最好的办法是设计你的 API 以返回一个Func<Task> or Func<Task<TResult>>。我已经做到了。

不幸的是,我的程序在安排第一组并发任务后挂起。假设我的任务并发度限制为 4。在这种情况下,将启动 4 个任务,然后程序将挂起。任务永远不会完成。

我创建了一个最小的例子来简单地说明问题。我正在使用文件读取而不是使用WebRequest。我将并发度限制为 1。

class Program
{
    static Func<Task> GetReadTask()
    {
        return () =>
        {
            Console.WriteLine("Opening file.");

            FileStream fileStream = File.Open("C:\\Users\\Joel\\Desktop\\1.txt", FileMode.Open);

            byte[] buffer = new byte[32];

            Console.WriteLine("Beginning read.");
            return Task<int>.Factory.FromAsync(fileStream.BeginRead, fileStream.EndRead, buffer, 0, 32, null).ContinueWith(task => fileStream.Close());
        };
    }

    static void Main()
    {
        LimitedConcurrencyLevelTaskScheduler ts = new LimitedConcurrencyLevelTaskScheduler(1);
        TaskFactory factory = new TaskFactory(ts);

        int[] range = {1, 2, 3};

        var tasks = range.Select(number =>
        {
            Func<Task> getTask = GetReadTask();
            return factory.StartNew(() =>
            {
                var task = getTask();
                task.Wait();
            });
        });

        Task.WaitAll(tasks.ToArray());
    }
}

为了澄清我所说的“它挂起”的意思,这就是输出的样子。

Opening file.
Beginning read.

然后就永远不会再打印任何其他内容。

关于发生什么事的任何线索?


好问题!

首先,我不确定LimitedConcurrencyLevelTaskScheduler是学术上正确的解决方案。为了将并发请求数限制为 N,您必须阻止 N 个任务,这从一开始就违背了使用 APM 异步调用的目的。

话虽如此,它比替代方案更容易实施。您需要有一个工作队列并记录正在进行的请求数量,然后根据需要创建工作任务。要做到这一点并不简单,如果并发请求的数量 N 很小,那么拥有 N 个阻塞线程并不是世界末日。

因此,您的代码的问题在于,在其他任务中创建的任务使用父任务中的调度程序。实际上,对于使用以下命令创建的任务来说并非如此FromAsync因为它们使用底层 APM 实现,所以有点不同。

您在中创建任务Main with:

return factory.StartNew( () =>
    {
        var task = getTask();
        task.Wait();
    }
);

factory使用LimitedConcurrencyLevelTaskScheduler( 1 ),因此这些任务中只有 1 个可以并发执行,并且其中一个正在等待从getTask().

So, in GetReadTask你打电话Task<int>.Factory.FromAsync。这是因为FromAsync不尊重父任务的调度程序。

然后你创建一个延续.ContinueWith(task => fileStream.Close())。这将创建一个尊重其父级调度程序的任务。自从LimitedConcurrencyLevelTaskScheduler已经在执行一项任务(Main被阻止了)延续无法运行并且出现死锁。

解决方案是在普通线程池线程上运行延续TaskScheduler.Default。然后它开始运行,僵局被打破。

这是我的解决方案:

static Task QueueReadTask( TaskScheduler ts, int number )
{
    Output.Write( "QueueReadTask( " + number + " )" );

    return Task.Factory.StartNew( () =>
        {
            Output.Write( "Opening file " + number + "." );

            FileStream fileStream = File.Open( "D:\\1KB.txt", FileMode.Open, FileAccess.Read, FileShare.Read );

            byte[] buffer = new byte[ 32 ];

            var tRead = Task<int>.Factory.FromAsync( fileStream.BeginRead, fileStream.EndRead, buffer, 0, 32, null );

            var tClose = tRead.ContinueWith( task =>
                    {
                        Output.Write( "Closing file " + number + ". Read " + task.Result + " bytes." );
                        fileStream.Close();
                    }
                    , TaskScheduler.Default
                );

            tClose.Wait();
        }
        , CancellationToken.None
        , TaskCreationOptions.None
        , ts
    );
}

And Main现在看起来像这样:

static void Main()
{
    LimitedConcurrencyLevelTaskScheduler ts = new LimitedConcurrencyLevelTaskScheduler( 1 );

    int[] range = { 1, 2, 3 };

    var tasks = range.Select( number =>
        {
            var task = QueueReadTask( ts, number );

            return task.ContinueWith( t => Output.Write( "Number " + number + " completed" ) );
        }
    )
    .ToArray();

    Output.Write( "Waiting for " + tasks.Length + " tasks: " + String.Join( " ", tasks.Select( t => t.Status ).ToArray() ) );

    Task.WaitAll( tasks );

    Output.Write( "WaitAll complete for " + tasks.Length + " tasks: " + String.Join( " ", tasks.Select( t => t.Status ).ToArray() ) );
}

有几点需要注意:

移动task.Wait() into QueueReadTask更明显地表明您正在阻止任务。您可以删除FromAsync调用和延续,并将它们替换为正常的同步调用,因为无论如何你都会阻塞。

任务返回自QueueReadTask可以有延续。默认情况下,它们在默认调度程序下运行,因为它们继承父任务的调度程序而不是前件任务的调度程序。在这种情况下,没有父任务,因此使用默认调度程序。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 LimitedConcurrencyLevelTask​​Scheduler 时延续任务挂起 的相关文章

  • 尝试在 ubuntu 中编译 android 内核时出错

    我正在尝试从源代码编译 Android 内核 并且我已经下载了所有正确的软件包来执行此操作 但由于某种原因我收到此错误 arm linux androideabi gcc error unrecognized command line op
  • HTTPWebResponse 响应字符串被截断

    应用程序正在与 REST 服务通信 Fiddler 显示作为 Apps 响应传入的完整良好 XML 响应 该应用程序位于法属波利尼西亚 在新西兰也有一个相同的副本 因此主要嫌疑人似乎在编码 但我们已经检查过 但空手而归 查看流读取器的输出字
  • OleDbDataAdapter 未填充所有行

    嘿 我正在使用 DataAdapter 读取 Excel 文件并用该数据填充数据表 这是我的查询和连接字符串 private string Query SELECT FROM Sheet1 private string ConnectStr
  • 如何从 appsettings.json 文件中的对象数组读取值

    我的 appsettings json 文件 StudentBirthdays Anne 01 11 2000 Peter 29 07 2001 Jane 15 10 2001 John Not Mentioned 我有一个单独的配置类 p
  • 关于 C++ 转换:参数 1 从“[some_class]”到“[some_class]&”没有已知的转换

    我正在研究 C 并且遇到了一个错误 我不知道确切的原因 我已经找到了解决方案 但仍然想知道原因 class Base public void something Base b int main Base b b something Base
  • 使用 WebClient 时出现 System.Net.WebException:无法创建 SSL/TLS 安全通道

    当我执行以下代码时 System Net ServicePointManager ServerCertificateValidationCallback sender certificate chain errors gt return t
  • WCF 中 SOAP 消息的数字签名

    我在 4 0 中有一个 WCF 服务 我需要向 SOAP 响应添加数字签名 我不太确定实际上应该如何完成 我相信响应应该类似于下面的链接中显示的内容 https spaces internet2 edu display ISWG Signe
  • 如何设计以 char* 指针作为类成员变量的类?

    首先我想介绍一下我的情况 我写了一些类 将 char 指针作为私有类成员 而且这个项目有 GUI 所以当单击按钮时 某些函数可能会执行多次 这些类是设计的单班在项目中 但是其中的某些函数可以执行多次 然后我发现我的项目存在内存泄漏 所以我想
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • Android 套接字和 asynctask

    我即将开始制作一个应该充当 tcp 聊天客户端的应用程序 我一直在阅读和阅读 我得出的结论是最好 如果不需要 将我的套接字和异步任务中的阅读器 问题是我不确定从哪里开始 因为我是 Android 新手 这至少对我来说是一项艰巨的任务 但据我
  • 向现有 TCP 和 UDP 代码添加 SSL 支持?

    这是我的问题 现在我有一个 Linux 服务器应用程序 使用 C gcc 编写 它与 Windows C 客户端应用程序 Visual Studio 9 Qt 4 5 进行通信 是什么very在不完全破坏现有协议的情况下向双方添加 SSL
  • 如何从两个不同的项目中获取文件夹的相对路径

    我有两个项目和一个共享库 用于从此文件夹加载图像 C MainProject Project1 Images 项目1的文件夹 C MainProject Project1 Files Bin x86 Debug 其中有project1 ex
  • C# 成员变量继承

    我对 C 有点陌生 但我在编程方面有相当广泛的背景 我想做的事情 为游戏定义不同的 MapTiles 我已经像这样定义了 MapTile 基类 public class MapTile public Texture2D texture pu
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • C# 模拟VolumeMute按下

    我得到以下代码来模拟音量静音按键 DllImport coredll dll SetLastError true static extern void keybd event byte bVk byte bScan int dwFlags
  • C# - OutOfMemoryException 在 JSON 文件上保存列表

    我正在尝试保存压力图的流数据 基本上我有一个压力矩阵定义为 double pressureMatrix new double e Data GetLength 0 e Data GetLength 1 基本上 我得到了其中之一pressur
  • C++ 标准是否指定了编译器的 STL 实现细节?

    在写答案时this https stackoverflow com questions 30909296 can you put a pimpl class inside a vector我遇到了一个有趣的情况 这个问题演示了这样一种情况
  • 如何防止用户控件表单在 C# 中处理键盘输入(箭头键)

    我的用户控件包含其他可以选择的控件 我想实现使用箭头键导航子控件的方法 问题是家长控制拦截箭头键并使用它来滚动其视图什么是我想避免的事情 我想自己解决控制内容的导航问题 我如何控制由箭头键引起的标准行为 提前致谢 MTH 这通常是通过重写
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两

随机推荐

  • HTML5 Canvas:更改图像颜色

    我有一个图像 灰度形式 我想更改其颜色 特定于用户 由于更改灰度图像的颜色非常困难 因此我提出了一种方法 图像分为两部分 一种是白色图像 其次 具有灰度的半透明图像 现在 我将两个图像放在彼此的顶部 白色图像在下面 灰度图像在上面 这样当我
  • 创建自定义复合按钮栏

    我必须在 Android 中创建一个自定义复合按钮栏控件 如下所示here http www coated com wp content uploads 2009 11 slacker radio android application j
  • Mockito - 没有为其中一个测试用例注入模拟

    我有一个 jsf spring 应用程序并使用mockito对于我的单元测试 我不断得到NullPointerException当我运行我的junit测试在iEmployeeService嘲笑 没有Exception for iSecuri
  • python:numpy 列表到数组和 vstack

    from scipy io wavfile import read filepath glob glob wav rates datas for fp in filepath rate data read fp rates append r
  • Nodejs CSV 数据导出系统供用户使用

    我需要允许用户以 csv 格式导出数据 我用nodejs写了应用程序 用户的导出数据可能非常庞大 所以我想知道如何在nodejs中处理这种情况 我应该使用nodejs的process nexttick还是子进程api 还有什么好的模块可用于
  • 当在静态上下文中使用实例方法时,为什么 javac 会发出“错误:类中的方法无法应用于给定类型”?

    考虑以下 无效 Java 程序 public class Test public static void main String args int ints 1 2 3 4 5 print ints public void print in
  • 更新 iOS 分发证书的正确方法

    我的分发证书以及我的所有配置文件将于 6 月 7 日到期 如何正确续订 我现在应该撤销它并申请新的吗 如果我这样做 我所有的实时应用程序都会被删除吗 您的实时应用程序不会被删除 应用商店中的任何内容都不会发生任何变化 一旦它们正式过期 唯一
  • 如何使用递归对数组的偶数和奇数求和

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我需要帮助创建一个递归函数 该函数接受数字列表 数组并返回元组或类似格式 a b where a是偶数之和并且b是奇数之和 例如 inpu
  • Java Swing:使用相应的键盘按钮时显示按下的按钮

    我正在使用 Swing 用 Ja va 编写一个程序 并使用包含箭头键的 GUI 方向键与键盘上的方向键相对应 当我按下键盘上的向上箭头键时 我希望 GUI 上的向上箭头键显示为被按下 在我释放箭头键之前 它应该显示它仍在被按下 并且当释放
  • 多条路线使用同一个控制器?

    有没有办法编写以下路由 这样您就不必每次都指定相同的控制器 get jobs gt pages jobs get contact gt pages contact get terms gt pages terms get privacy g
  • 如何从 GitHub Actions 中的重定向输出中删除所有无关输出?

    我有一个使用 Terraform 进行部署的 GitHub Actions 工作流程 当 Terraform 完成后 我想获取 Terraform 输出并将其发送到工作流程中的下一个作业 以便可以提取和使用各个部分 具体来说 我的 Terr
  • 如何让 XML 注释出现在不同的项目 (dll) 中?

  • ClusterManager 重新绘制 Google 地图 v2 实用程序的标记

    我正在发出服务器请求 当我收到服务器的响应时 我正在 UI 线程上执行ClusterManager addItem 但这个项目没有在地图上绘制 只有当我进行缩放更新 时 新添加的项目才开始出现 我也尝试调试渲染器 但是onBeforeClu
  • 从 Android 中的 DatePickerDialog 中删除标题

    我想将 DatePickerDialog 限制为明天的最小值 当我输入下面显示的代码时 限制就起作用了 但是 包含日期的标题文本看起来像标题 我怎样才能解决这个问题 这是我的代码 Calendar tempDate Calendar get
  • WASAPI:选择专用输出的波形格式

    我正在尝试使用 WASAPI 打开带有输出设备的独占流 我在选择可接受的格式时遇到了困难 因为似乎没有关于给定设备接受哪些格式的提示 就我而言 IAudioClient GetMixFormat 否则会返回设备的一种默认格式 返回一种不能在
  • 排序错误

    我正在使用 Microsoft SQL Server Management Studio 我有两个数据库 一个是系统数据库 其中包含 master 数据库 另一个是我的数据库 名为CCTNS CAS DE DB 当我尝试通过使用以下工具的工
  • Android 在等待位置时显示进度对话框

    我正在使用以下示例开发基于位置的应用程序 http www androidhive info 2012 07 android gps location manager tutorial http www androidhive info 2
  • C# 中的高质量图形/波形显示组件

    我正在寻找一种使用 C 编写的快速 专业外观且可定制的波形显示组件 我想在时域和频域中主要显示实时音频波形 快 我希望能够缩放 更改轴设置 显示多个通道 自定义感觉和颜色等 有人知道任何事情吗 无论是商业的还是非商业的 谢谢你 Diego
  • 在 Git 中切换分支不会删除目录

    我在 Git 中创建了两个分支 git branch F1 git branch F2 接下来 我切换到 F1 git checkout F1 I rename my UnitTests目录到Tests git mv UnitTests T
  • 使用 LimitedConcurrencyLevelTask​​Scheduler 时延续任务挂起

    我正在研究在 C NET 4 0 中使用 TPL 我创建了一个自定义 API 来简化 Web 请求的创建和下载内容 异步 使用延续任务 那部分工作正常 当我尝试使用时出现的问题LimitedConcurrencyLevelTaskSched