- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
最近我开始尝试大量抓取一个网站以用于存档目的,我认为让多个 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();
}
当 run 得出这个结果时:
如您所见,前四个任务以约 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 .
关于c# - 异步任务 'Clogging',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28314695/
有没有人有一个例子来说明如何重新定义 C++ 内置的 clog,而不是有一个新的关联 rdbuf(),它被处理为原始 clog.rdbuf() 和 ofstream 对象的 rdbuf() 的三通到磁
最近我开始尝试大量抓取一个网站以用于存档目的,我认为让多个 Web 请求异步工作以加快处理速度是个好主意(10,000,000 个页面肯定需要大量存档)等等我冒险进入并行性的严酷女主人,三分钟后我开始
我正在做什么:我正在浏览数据库中的公司表...每个公司都有一个文本description字段,并且在该字段内可以有许多超链接(很少超过 4 个)。我想做的是使用 curl 测试这些链接的“不良”响应(
我已经安装了主-主复制。 一切正常,直到您断开两个服务器之间的链接。 一旦被破坏,如果超过某种限制,数据将不会从一个数据转移到另一个数据。 Max_packet 大小设置为 500mb。 但是,如果您
我要编译CLOGS library.I follow this手动的。我在 windows 10 x64 中使用 Visual Studio 2010,python 3.4。我对waf构建系统一无所知
我需要一个类来包装对 std::clog 的调用这样: 每条消息都带有标题前缀,其中包括时间和生成消息的实体的名称。 消息根据错误类型(例如调试、警告、错误)进行着色。 使用方式完全等同于std::c
两个排序的整数数组 A[1..N] 和 B[1..N] 按升序提供。 问题:设计一个O(log N)-time 算法来找出所有 2N 个整数的中位数。 N 可能不是 2 的幂。 为了简单起见,我们可以
在开发代码时,我有很多控制台日志记录 (std::clog) 和一些控制台输出 (std::cout)。但是现在,我想在线提交我的源代码,我想禁用所有控制台日志记录 (clog) 但保留控制台输出 (
这个问题在这里已经有了答案: What is the point of clog? (6 个答案) 关闭 7 年前。 我的代码中有一个基本的调试消息,它打印一条关于调用什么函数的消息。 #ifdef
以下程序在使用 g++ 退出后出现段错误: #include #include
这里的一个相关问题展示了如何只用木屐来做到这一点: How to redefine clog to tee to original clog and a log file? 现在的问题是如何同时为 c
我想创建一个类似流的类,通过它我可以写入 std::out 和 std::clog。 我有以下代码,但问题是它只写入 std::clog,而控制台上的输出并不像预期的那样(奇怪的是,它覆盖了自己)。
我知道目前的C++中没有线程的概念,但是this article is saying : A typesafe, threadsafe, portable logging mechanism ....
iostream 对象 cin、cout、cerr 和 clog 是在 iostream header 中声明的对象。 我知道在某些编译器中可能会在构造这些 iostream 对象之前尝试使用它们,因
cout、cin、cerr 和 clog 名称中的“c”是什么意思? 我会说 char 但我没有找到任何可以确认的东西。 最佳答案 The "c" stands for "character" bec
我在 Unix 上开发一个向 syslog 发送消息的 C++ 程序。 当前代码使用类似于 printf 的 syslog 系统调用。 现在我更愿意为此目的使用流,通常是内置的 std::clog。但
我在 ng-model 文档中摆弄 Angular 自己的站点使用的 plunker: http://plnkr.co/edit/?p=preview 如果将 $scope.val 设置为其中包含“”
log() = log base 2 of ()log()^2 = log^2 base 2 of ()我被这个归纳证明困住了。我有以下递归关系T(n) = T(n/2) + Theta(log(n)
我是一名优秀的程序员,十分优秀!