异步任务“堵塞”

2023-11-23

最近,我开始尝试大规模抓取网站以进行存档,我认为让多个 Web 请求异步工作以加快速度是一个好主意(10,000,000 个页面绝对需要存档),因此我冒险进入并行性的严厉女主人,三分钟后我开始想知道为什么我正在创建的任务(通过Task.Factory.StartNew)正在“堵塞”。

既恼火又好奇,我决定对此进行测试,看看这是否只是环境造成的,所以我在 VS2012 中创建了一个新的控制台项目并创建了以下内容:

static void Main(string[] args)
{
    for (int i = 0; i < 10; i++) {
        int i2 = i + 1;
        Stopwatch t = new Stopwatch();
        t.Start();
        Task.Factory.StartNew(() => {
            t.Stop();
            Console.ForegroundColor = ConsoleColor.Green; //Note that the other tasks might manage to write their lines between these colour changes messing up the colours.
            Console.WriteLine("Task " + i2 + " started after " + t.Elapsed.Seconds + "." + t.Elapsed.Milliseconds + "s");
            Thread.Sleep(5000);
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("Task " + i2 + " finished");
        });
    }
    Console.ReadKey();
}

当运行时得出这个结果:

Test results

正如您所看到的,前四个任务快速连续启动,时间约为 0.27,但是此后任务开始所需的时间急剧增加。

为什么会发生这种情况?我可以采取什么措施来修复或绕过此限制?


任务(默认情况下)在线程池上运行,顾名思义,线程池是一个线程池。线程池针对很多情况进行了优化,但是抛出Thread.Sleep那里可能会给大多数人带来麻烦。还,Task.Factory.StartNew通常来说这是一个坏主意,因为人们不理解它是如何工作的。试试这个:

static void Main(string[] args)
{
    for (int i = 0; i < 10; i++) {
        int i2 = i + 1;
        Stopwatch t = new Stopwatch();
        t.Start();
        Task.Run(async () => {
            t.Stop();
            Console.ForegroundColor = ConsoleColor.Green; //Note that the other tasks might manage to write their lines between these colour changes messing up the colours.
            Console.WriteLine("Task " + i2 + " started after " + t.Elapsed.Seconds + "." + t.Elapsed.Milliseconds + "s");
            await Task.Delay(5000);
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("Task " + i2 + " finished");
        });
    }
    Console.ReadKey();
}

更多解释:

线程池可使用的线程数量有限。这个数字会根据某些条件而变化,但一般来说它是正确的。因此,您永远不应该在线程池上执行任何阻塞操作(如果您想实现并行性)。Thread.Sleep是阻塞 API 的完美示例,但大多数 Web 请求 API 也是如此,除非您使用较新的异步版本。

因此,您的原始爬行程序中的问题可能与您发布的示例中的问题相同。您正在阻塞所有线程池线程,因此它被迫启动新线程,并最终导致堵塞。

额外的好东西

巧合的是,使用Task.Run通过这种方式,您还可以轻松地重写代码,以便您可以知道代码何时完成。通过存储对所有已启动任务的引用,并在最后等待所有任务(这不会妨碍并行性),您可以可靠地知道所有任务何时完成。下面展示了如何实现这一目标:

static void Main(string[] args)
{
    var tasks = new List<Task>();
    for (int i = 0; i < 10; i++) {
        int i2 = i + 1;
        Stopwatch t = new Stopwatch();
        t.Start();
        tasks.Add(Task.Run(async () => {
            t.Stop();
            Console.ForegroundColor = ConsoleColor.Green; //Note that the other tasks might manage to write their lines between these colour changes messing up the colours.
            Console.WriteLine("Task " + i2 + " started after " + t.Elapsed.Seconds + "." + t.Elapsed.Milliseconds + "s");
            await Task.Delay(5000);
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("Task " + i2 + " finished");
        }));
    }
    Task.WaitAll(tasks.ToArray());
    Console.WriteLine("All tasks completed");
    Console.ReadKey();
}

注意:此代码未经测试

阅读更多

更多信息:Task.Factory.StartNew以及为什么应该避免:http://blog.stephencleary.com/2013/08/startnew-is-dangerous.html.

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

异步任务“堵塞” 的相关文章

  • 计算 XML 中特定 XML 节点的数量

    请参阅此 XML
  • 如何在多线程C++ 17程序中交换两个指针?

    我有两个指针 pA 和 pB 它们指向两个大的哈希映射对象 当pB指向的哈希图完全更新后 我想交换pB和pA 在C 17中 如何快速且线程安全地交换它们 原子 我是 c 17 的新手 2个指针的原子无等待交换可以通过以下方式实现 inclu
  • ComboBox DataBinding 导致 ArgumentException

    我的几个类对象 class Person public string Name get set public string Sex get set public int Age get set public override string
  • 查找进程的完整路径

    我已经编写了 C 控制台应用程序 当我启动应用程序时 不使用cmd 我可以看到它列在任务管理器的进程列表中 现在我需要编写另一个应用程序 在其中我需要查找以前的应用程序是否正在运行 我知道应用程序名称和路径 所以我已将管理对象搜索器查询写入
  • 如何判断计算机是否已重新启动?

    我曾经使用过一个命令行 SMTP 邮件程序 作为试用版的限制 它允许您在每个 Windows 会话中最多接收 10 封电子邮件 如果您重新启动计算机 您可能还会收到 10 个以上 我认为这种共享软件破坏非常巧妙 我想在我的应用程序中复制它
  • JNI 将 Char* 2D 数组传递给 JAVA 代码

    我想从 C 代码通过 JNI 层传递以下指针数组 char result MAXTEST MAXRESPONSE 12 12 8 3 29 70 5 2 42 42 在java代码中我写了以下声明 public static native
  • 如何填充 ToolStripComboBox?

    我发现它很难将数据绑定到ToolStripComboBox 好像没有这个ValueMember and DisplayMember特性 怎么绑定呢 访问toolstripcombobox中包装的组合框并访问其ValueMember Disp
  • 为什么在 WebApi 上下文中在 using 块中使用 HttpClient 是错误的?

    那么 问题是为什么在 using 块中使用 HttpClient 是错误的 但在 WebApi 上下文中呢 我一直在读这篇文章不要阻止异步代码 https blog stephencleary com 2012 07 dont block
  • 为什么可以通过ref参数修改readonly字段?

    考虑 class Foo private readonly string value public Foo Bar ref value private void Bar ref string value value hello world
  • 如何在 Qt 应用程序中通过终端命令运行分离的应用程序?

    我想使用命令 cd opencv opencv 3 0 0 alpha samples cpp cpp example facedetect lena jpg 在 Qt 应用程序中按钮的 clicked 方法上运行 OpenCV 示例代码
  • IQueryable 单元或集成测试

    我有一个 Web api 并且公开了一个端点 如下所示 api 假期 name name 这是 Web api 的控制器 get 方法 public IQueryable
  • 在视口中查找 WPF 控件

    Updated 这可能是一个简单或复杂的问题 但在 wpf 中 我有一个列表框 我用一个填充数据模板从列表中 有没有办法找出特定的数据模板项位于视口中 即我已滚动到其位置并且可以查看 目前我连接到了 listbox ScrollChange
  • 在屏幕上获取字符

    我浏览了 NCurses 函数列表 似乎找不到返回已打印在屏幕上的字符的函数 每个字符单元格中存储的字符是否有可访问的值 如果没有的话Windows终端有类似的功能吗 我想用它来替换屏幕上某个值的所有字符 例如 所有a s 具有不同的特征
  • WebBrowser.Print() 等待完成。 。网

    我在 VB NET 中使用 WebBrowser 控件并调用 Print 方法 我正在使用 PDF 打印机进行打印 当调用 Print 时 它不会立即启动 它会等到完成整个子或块的运行代码 我需要确保我正在打印的文件也完整并继续处理该文件
  • OpenGL:仅获取模板缓冲区而没有深度缓冲区?

    我想获取一个模板缓冲区 但如果可能的话 不要承受附加深度缓冲区的开销 因为我不会使用它 我发现的大多数资源表明 虽然模板缓冲区是可选的 例如 排除它以利于获得更高的深度缓冲区精度 但我还没有看到任何请求并成功获取仅 8 位模板缓冲区的代码
  • 这个可变参数模板示例有什么问题?

    基类是 include
  • 可访问性不一致:参数类型的可访问性低于方法

    我试图在两个表单之间传递一个对象 基本上是对当前登录用户的引用 目前 我在登录表单中有一些类似的内容 private ACTInterface oActInterface public void button1 Click object s
  • 使用 MPI 的 Allreduce 对 Python 对象求和

    我正在使用使用 Python 中的字典和计数器构建的稀疏张量数组操作 我想让并行使用这个数组操作成为可能 最重要的是 我最终在每个节点上都有计数器 我想使用 MPI Allreduce 或另一个不错的解决方案 将其添加在一起 例如 使用计数
  • 灵气序列解析问题

    我在使用 Spirit Qi 2 4 编写解析器时遇到一些问题 我有一系列键值对以以下格式解析
  • 不区分大小写的字符串比较 C++ [重复]

    这个问题在这里已经有答案了 我知道有一些方法可以进行忽略大小写的比较 其中涉及遍历字符串或一个good one https stackoverflow com questions 11635 case insensitive string

随机推荐

  • 填充可用空间的 CSS 布局

    我正在尝试做一个看似简单的网页布局 但我遇到了困难 I d like做一切事纯粹用CSS 没有桌子把事情搞砸 并且没有 JavaScript动态调整事物的大小 我想要 具有固定高度的标题 固定高度的页脚 具有固定宽度的左侧边栏 具有固定宽度
  • UICollectionViewLayoutlayoutAttributesForElementsInRect和layoutAttributesForItemAtIndexPath

    我正在实现自定义流程布局 它有两种主要方法来覆盖以确定单元格的位置 layoutAttributesForElementsInRect and layoutAttributesForItemAtIndexPath 在我的代码中 layout
  • 如何将单行与sql中列中的数字相乘

    就我而言 有订单和订单头寸 每个订单位置都有一个数量 例如 但现在我需要每个 位置元素 一行 这是我想要的输出 我的想法是使用rank over 获得增量数 但我不知道如何使用该数量作为乘数 是否有一个聪明的解决方案来使用单列作为 行乘法器
  • 删除变量上的重复项而不进行排序

    我有一个变量 其中包含以下空格分隔的条目 variable apple lemon papaya avocado lemon grapes papaya apple avocado mango banana 如何在不排序的情况下删除重复项
  • Python 行尾正则表达式

    我正在尝试编写一个正则表达式 在点之前和之后添加一个空格 但是 我只希望在点后有空格或行尾时出现此情况 但是 对于行尾情况 我无法这样做 Eg I want a hotel gt gt I want a hotel my email is
  • 如何在iPhone上播放MIDI?

    据我所知 没有本地或第三方库可用于在 iPhone 上播放 MIDI 但似乎有不少应用程序可以做到这一点 他们用什么 有什么线索吗 供那些走这条路的人参考 AVMIDIPlayer 是在 iOS 8 中引入的 似乎在设备上运行良好 但 si
  • C++ JSON 序列化

    我想要一种尽可能自动地将对象序列化和反序列化为 JSON 的方法 连载 对我来说 理想的方法是 如果我调用实例 JSONSerialize 它会返回一个带有 JSON 对象的字符串 该对象具有该对象的所有公共属性 name of prope
  • 如何从段落 python docx 中获取图像(inlineshape)

    我想逐段阅读docx文档 如果有图片 InlineShape 则用它周围的文本处理它 函数 Document inline shapes 将给出文档中所有内联形状的列表 但我想得到一个 如果存在的话 恰好出现在当前段落中 代码示例 from
  • Eclipse 中模板的 Django 标签

    我想知道是否可以在 Eclipse IDE 中为基于 Django 的模板提供自动完成 自动格式化和这些漂亮的功能 主要是为了这些事情 提前致谢 检查此页面以获取 Django Eclipse 插件 http eclipse kacprza
  • 如何使用 Java IO 读取 Windows NTFS 备用数据流?

    我试图让我的 Java 应用程序读取给定路径中的所有数据 文件 目录 元数据等 这还包括 NTFS 称为备用数据流 ADS 的一个奇怪的东西 显然 它就像目录或文件中的第二层数据 您可以打开命令提示符并使用 在ADS中创建文件 例如 C A
  • 如何在eclipse中显示日语字符[重复]

    这个问题在这里已经有答案了 我使用 eclipse Juno 作为 Java IDE 并且在我的 java 代码中注释和日志记录语句都是日语的 eclipse 显示垃圾字符而不是正确的日语字符 我跟着这个帖子解决该问题并在 eclipse
  • 在 Xcode 5 上使用 Boost - Apple LLVM 5.0

    由于只有一个编译器 LLVM 5 0 我在构建 Xcode 5 的 Boost 时遇到了问题 我尝试过使用 c 11 使用 clang 来使用 Homebrew 我尝试过各种想法和脚本 但到目前为止没有一个有效 要为使用 clang llv
  • 在 Django Rest Framework 选项请求中显示过滤器和排序

    我正在使用 Django Rest Framework 我注意到 API 的 Web 可浏览部分有一个名为 选项 的按钮 单击它会显示以下内容 HTTP 200 OK Vary Accept Content Type text html A
  • ASP.NET MVC 4 缩小和背景图像

    我目前正在使用 ASP NET MVC 4 CSS JavaScript 优化器 它与我自己的 CSS JavaScript 配合得很好 但我也想将它与插件一起使用 每个插件都有自己的文件夹 Content css my own css o
  • 上个月的最后一天 - BigQuery

    我正在尝试选择其中时间戳字段 recdate 的日期值高达并包含该月最后完成日期的行 例如 由于现在是 2016 年 7 月 我希望所有行的日期值在 2016 年 6 月 31 日 含 之前 这曾经在 T SQL 中工作得很好 我会使用以下
  • 无法连接到 mySQL 数据库

    所以我在使用 Java 连接 MySQL 时遇到问题 这是我的代码 import java sql Connection import java sql DriverManager import java sql SQLException
  • JQuery 延迟立即拒绝

    使用JQuery Deferred时可以直接调用reject 吗 没有调用异步函数 也许我想在异步函数的开头进行某种测试 如果测试失败我想立即拒绝 请参阅下面的第一个 if 块 function doSomethingAsync Test
  • 用于选择的 Angular 2 RouterLink

    我想使用页面上的选择元素创建导航 在锚标记上使用 RouterLink 指令很简单 但是选择下拉菜单是否有等效的指令 或者我是否需要在我的组件上创建自己的导航方法 以便在我的选择发生更改时调用 a Location a
  • 计时器刻度不增加时间间隔的值

    我想增加计时器滴答事件的值 但它没有增加 不知道我忘记了什么 它只显示1
  • 异步任务“堵塞”

    最近 我开始尝试大规模抓取网站以进行存档 我认为让多个 Web 请求异步工作以加快速度是一个好主意 10 000 000 个页面绝对需要存档 因此我冒险进入并行性的严厉女主人 三分钟后我开始想知道为什么我正在创建的任务 通过Task Fac