天道酬勤,学无止境

在 C# 中,顺序循环如何比并行循环运行得更快?(How does sequential loop run faster than Parallel loop in C#?)

问题

我尝试了一个非常小的例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Concurrent;
using System.Diagnostics;

namespace TPLExample {
    class Program {
        static void Main(string[] args) {
            int[] dataItems = new int[100];
            double[] resultItems = new double[100];

            for (int i = 0; i < dataItems.Length; ++i) {
                dataItems[i] = i;
            }

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Reset();
            stopwatch.Start();
            Parallel.For(0, dataItems.Length, (index) => {
                resultItems[index] = Math.Pow(dataItems[index], 2);
            });
            stopwatch.Stop();
            Console.WriteLine("TPL Time elapsed: {0}", stopwatch.Elapsed);

            stopwatch.Reset();
            stopwatch.Start();
            for (int i = 0; i < dataItems.Length; ++i) {
                resultItems[i] = Math.Pow(dataItems[i], 2);
            }
            stopwatch.Stop();
            Console.WriteLine("Sequential Time elapsed: {0}", stopwatch.Elapsed);

            WaitForEnterKey();
        }

        public static void WaitForEnterKey() {
            Console.WriteLine("Press enter to finish");
            Console.ReadLine();
        }

        public static void PrintMessage() {
            Console.WriteLine("Message printed");
        }
    }
}

输出是:

TPL Time elapsed: 00:00:00.0010670
Sequential Time elapsed: 00:00:00.0000178
Press enter to finish

顺序循环比 TPL 快得多! 这怎么可能? 根据我的理解, Parallel.For计算将Parallel.For执行,所以它必须更快吗?

回答1

简单地说:对于仅迭代一百多个项目并执行一个小的数学运算,产生新线程并等待它们完成会产生比仅仅运行循环更多的开销。

根据我的理解,Parallel.For 中的计算将并行执行,所以它必须更快吗?

当人们对计算机性能做出全面的陈述时,通常会发生这种情况,这里有更多的变量在起作用,你不能真正做出这种假设。 例如,在您的for循环中,您所做的只是Math.Pow ,处理器可以非常快速地执行它。 如果这是一个 I/O 密集型操作,需要每个线程等待很长时间,或者即使是一系列处理器密集型操作,你也会从并行处理中获得更多(假设你有一个多线程处理器) . 但事实上,创建和同步这些线程的开销远远大于并行性可能给您带来的任何优势。

回答2

当在循环内执行的操作成本相对较高时,并行循环处理是有益的。 你在你的例子中所做的就是计算一个指数,这是微不足道的。 多线程的开销远远超过您在这种情况下获得的收益。

回答3

这个代码示例是上面非常好的答案的实际证明。

我通过 Thead.Sleep 简单地阻塞线程来模拟密集的处理器操作。

输出是:

  • 顺序循环 - 00:00:09.9995500
  • 并行循环 - 00:00:03.0347901

_

class Program
{
    static void Main(string[] args)
    {
        const int a = 10;

        Stopwatch sw = new Stopwatch();
        sw.Start();

        //for (long i = 0; i < a; i++)
        //{
        //    Thread.Sleep(1000);
        //}

        Parallel.For(0, a, i =>
        {
            Thread.Sleep(1000);
        });

        sw.Stop();

        Console.WriteLine(sw.Elapsed);

        Console.ReadLine();
    }
}
回答4

并行化的开销远远大于简单地按顺序运行 Math.Pow 100 次。 其他人都这么说了。

更重要的是,虽然在顺序版本中内存访问是微不足道的,但在并行版本中,线程必须共享内存(resultItems),即使您有一百万个项目,这种事情也会真正杀死您。

请参阅这篇关于并行编程的优秀Microsoft 白皮书的第 44 页:http://www.microsoft.com/en-us/download/details.aspx?id=19222。 这是有关该主题的 MSDN 杂志文章:http://msdn.microsoft.com/en-us/magazine/cc872851.aspx

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 异步运行同一方法的多个实例?(Run multiple instances of same method asynchronously?)
    问题 我的要求很奇怪。 我有SomeMethod()调用GetDataFor() 。 public void SomeMethod() { for(int i = 0; i<100; i++) { var data = GetDataFor(i); } } public data GetDataFor(int i) { //call a remote API //to generate data for i //store to database return data; } 对于每个i ,最终结果总是不同的。 在调用GetDataFor(i+1)之前无需等待GetDataFor(i)完成。 换句话说,我需要: 成功调用i后立即为每个i+1调用GetDataFor() (并行调用它们看起来不可能) 等到GetDataFor()所有100 个实例都完成运行离开SomeMethod()的范围 按照 YK1 的回答,我尝试像这样修改它: public async Task<void> SomeMethod() { for(int i = 0; i < 100; i++) { var task = Task.Run(() => GetDataFor(i)); var data = await task; } } 它没有抛出任何错误,但我需要了解这背后的概念:
  • 在 C# 中加速矩阵加法(Speed up Matrix Addition in C#)
    问题 我想优化这段代码: public void PopulatePixelValueMatrices(GenericImage image,int Width, int Height) { for (int x = 0; x < Width; x++) { for (int y = 0; y < Height; y++) { Byte pixelValue = image.GetPixel(x, y).B; this.sumOfPixelValues[x, y] += pixelValue; this.sumOfPixelValuesSquared[x, y] += pixelValue * pixelValue; } } } 这将用于图像处理,我们目前正在为大约 200 张图像运行它。 我们已经优化了 GetPixel 值以使用不安全的代码,并且我们没有使用 image.Width 或 image.Height,因为这些属性会增加我们的运行时成本。 然而,我们仍然停留在低速。 问题是我们的图像是 640x480,所以循环的中间被调用了大约 640x480x200 次。 我想问一下是否有办法以某种方式加速它,或者让我相信它已经足够快了。 也许一种方法是通过一些快速的矩阵加法,或者矩阵加法本质上是一个 n^2 操作而无法加速它? 也许通过不安全代码进行数组访问会加快速º
  • 不得已的性能优化策略[关闭](Performance optimization strategies of last resort [closed])
    问题 关门了。 这个问题需要更加集中。 它当前不接受答案。 想要改善这个问题吗? 更新问题,使其仅通过编辑此帖子即可将重点放在一个问题上。 7年前关闭。 改善这个问题 这个站点上已经存在很多性能问题,但是据我所知,几乎所有问题都是针对特定问题的,而且范围很窄。 几乎所有人都会重复建议,以免过早优化。 假设: 该代码已经正常工作选择的算法已经针对问题的环境进行了优化该代码已被测量,并且令人讨厌的例程已被隔离所有优化的尝试也将得到衡量,以确保它们不会使情况变得更糟 我在这里寻找的是策略和技巧,这些方法和技巧可以使关键算法中的最后几个部分都挤到最后一个百分点,而这除了需要做的事情外,别无其他。 理想情况下,尝试使答案与语言无关,并在适用的情况下指出建议策略的任何弊端。 我将添加带有我自己的初步建议的答复,并期待Stack Overflow社区可以想到的其他任何东西。 回答1 好的,您正在将问题定义为似乎没有太多改进空间的地方。 以我的经验,那是相当罕见的。 我试图在1993年11月的Dobbs博士的一篇文章中对此进行解释,从一个常规设计良好,无明显浪费的平凡程序开始,并对其进行了一系列优化,直到其挂钟时间从48秒减少到到1.1秒,源代码的大小减少了4倍。我的诊断工具就是这个。 更改的顺序是这样的: 发现的第一个问题是使用列表集群(现在称为“迭代器”和“容器类”)占了一半以上的时间。
  • 现代如何使用汇编(例如,使用 C/C++)?(How is Assembly used in the modern day (with C/C++ for example)?)
    问题 我了解计算机如何根据基本原理工作,例如,可以用 C#、C 等“高级”语言编写程序,然后将其分解为目标代码,然后再分解为二进制供处理器理解。 但是,我真的很想了解汇编,以及它如何在现代应用程序中使用。 我知道处理器在基本 x86 指令集之上有不同的指令集。 所有汇编语言都支持所有指令集吗? 有多少种汇编语言? 有多少可以与其他语言一起使用? 有人将如何在汇编中编写例程,然后将其编译为对象/二进制代码? 然后有人如何从 C 或 C++ 之类的语言中引用该汇编代码中的函数/例程? 我们怎么知道我们用汇编编写的代码可能是最快的? 是否有关于汇编语言/将它们与现代程序一起使用的推荐书籍? 抱歉问题的数量太多,我确实希望它们足够通用以对其他人有用,并且足够简单以供其他人回答! 回答1 但是,我真的很想了解汇编,以及它如何在现代应用程序中使用。 在“普通”PC 上,它仅用于对时间要求严格的处理,我想说实时多媒体处理仍然可以从手工组装中受益很多。 在马力较小的嵌入式系统上,它可能有更多的使用领域。 然而,请记住,这不仅仅是“嘿,这段代码很慢,我会用汇编重写它,它会神奇地运行得很快”:它必须仔细编写汇编,知道什么是快的,什么是慢的在您的特定架构上,并牢记现代处理器的所有复杂性(分支错误预测、乱序执行等)。 通常,由初级到中级汇编程序员编写的程序集比由优秀的现代优化编译器生成的最终机器代码慢。
  • 循环索引的C语言:在新CPU中正向索引速度更快吗?(C for loop indexing: is forward-indexing faster in new CPUs?)
    问题 在我订阅的邮件列表中,两个相当博学的(IMO)程序员正在讨论一些优化的代码,并说出一些类似的内容: 在5到8年前发布的CPU上,向后迭代的循环稍微快一些(例如, for (int i=x-1; i>=0; i--) {...} ),因为将i与零进行比较比将它与其他数字进行比较更有效。 但是对于最近的CPU(例如,从2008-2009年开始),推测性加载器逻辑使得如果向前循环for循环则可以更好地工作(例如, for (int i=0; i< x; i++) {...} ) 。 我的问题是,这是真的吗? CPU的实现方式最近是否发生了变化,以至于正向循环迭代现在比反向迭代具有优势? 如果是这样,对此有何解释? 即发生了什么变化? (是的,我知道,过早的优化是万恶之源,请在担心微优化之前查看我的算法,等等。。。我主要是好奇的) 回答1 您实际上是在询问预取,而不是循环控制逻辑。 通常,循环性能不会由控制逻辑来决定(即,增量/减量和每次通过检查的条件)。 除了非常紧密的循环外,执行这些操作所花费的时间是无关紧要的。 如果您对此感兴趣,请查看约翰·诺勒(John Knoeller)在8086柜台计数器上提供的详细信息的答案,以及为什么在过去的日子里倒计时更有效可能是正确的。 正如约翰所说,分支预测(以及推测)在这里可以起到性能的作用,指令预取也可以。
  • 递归比循环快吗?(Is recursion ever faster than looping?)
    问题 我知道有时候递归比循环要干净得多,而且我什么时候不应该在迭代中使用递归就没有任何疑问,我知道已经有很多问题了。 什么我问的是,是递归以前所未有的速度比一个循环? 在我看来,与循环函数相比,您总是能够完善一个循环并使其执行得更快,因为没有循环不断地建立新的堆栈框架。 我专门在寻找在应用程序中递归是处理数据正确方式的应用程序中递归是否更快,例如在某些排序函数中,在二叉树中等等。 回答1 这取决于所使用的语言。 您编写了“与语言无关”的文章,因此我将举一些例子。 在Java,C和Python中,与迭代(通常)相比,递归的开销相当大,因为它需要分配新的堆栈框架。 在某些C编译器中,可以使用编译器标志消除这种开销,该开销将某些类型的递归(实际上是某些类型的尾部调用)转换为跳转而不是函数调用。 在函数式编程语言实现中,有时迭代可能会非常昂贵,而递归可能会非常便宜。 在许多情况下,递归转换为简单的跳转,但是更改循环变量(可变的)有时需要进行一些相对繁重的操作,尤其是在支持多个执行线程的实现上。 在某些这样的环境中,如果变量和垃圾回收器可能同时运行,则由于它们之间的交互作用,导致突变的代价很高。 我知道在某些Scheme实现中,递归通常比循环快。 简而言之,答案取决于代码和实现。 使用您喜欢的任何样式。 如果您使用的是功能语言,则递归速度可能会更快。 如果您使用命令式语¨
  • 任务并行不稳定,有时使用 100% CPU(Task Parallel is unstable, using 100% CPU at times)
    问题 我目前正在测试 C# 的 Parallel。 通常它工作正常,并且使用并行比普通的 foreach 循环更快。 但是,有时(例如 5 次中有 1 次),我的 CPU 将达到 100% 的使用率,从而导致并行任务非常缓慢。 我的 CPU 设置是 i5-4570 和 8GB 内存。 有谁知道为什么会出现这个问题? 下面是我用来测试功能的代码 // Using normal foreach ConcurrentBag<int> resultData = new ConcurrentBag<int>(); Stopwatch sw = new Stopwatch(); sw.Start(); foreach (var item in testData) { if (item.Equals(1)) { resultData.Add(item); } } Console.WriteLine("Normal ForEach " + sw.ElapsedMilliseconds); // Using list parallel for resultData = new ConcurrentBag<int>(); sw.Restart(); System.Threading.Tasks.Parallel.For(0, testData.Count() - 1, (i, loopState) =
  • OpenMP-在外部循环之前进行并行处理时,嵌套的for循环会变得更快。 为什么?(OpenMP - Nested for-loop becomes faster when having parallel before outer loop. Why?)
    问题 我目前正在实施一种动态编程算法来解决背包问题。 因此,我的代码有两个for循环,一个外部循环和一个内部循环。 从逻辑角度来看,我可以并行化内部for循环,因为那里的计算是相互独立的。 由于依赖关系,外部for循环无法并行化。 所以这是我的第一种方法: for(int i=1; i < itemRows; i++){ int itemsIndex = i-1; int itemWeight = integerItems[itemsIndex].weight; int itemWorth = integerItems[itemsIndex].worth; #pragma omp parallel for if(weightColumns > THRESHOLD) for(int c=1; c < weightColumns; c++){ if(c < itemWeight){ table[i][c] = table[i-1][c]; }else{ int worthOfNotUsingItem = table[i-1][c]; int worthOfUsingItem = itemWorth + table[i-1][c-itemWeight]; table[i][c] = worthOfNotUsingItem < worthOfUsingItem
  • 为什么用于测试Collat​​z猜想的C ++代码比手写汇编运行得更快?(Why does C++ code for testing the Collatz conjecture run faster than hand-written assembly?)
    问题 我用汇编语言和C ++语言为Euler Q14项目编写了这两种解决方案。 他们采用相同的蛮力方法来测试Collat​​z猜想。 组装解决方案通过以下方式组装: nasm -felf64 p14.asm && gcc p14.o -o p14 C ++使用以下命令进行编译: g++ p14.cpp -o p14 汇编, p14.asm : section .data fmt db "%d", 10, 0 global main extern printf section .text main: mov rcx, 1000000 xor rdi, rdi ; max i xor rsi, rsi ; i l1: dec rcx xor r10, r10 ; count mov rax, rcx l2: test rax, 1 jpe even mov rbx, 3 mul rbx inc rax jmp c1 even: mov rbx, 2 xor rdx, rdx div rbx c1: inc r10 cmp rax, 1 jne l2 cmp rdi, r10 cmovl rdi, r10 cmovl rsi, rcx cmp rcx, 2 jne l1 mov rdi, fmt xor rax, rax call printf ret C ++, p14.cpp :
  • C# 中的 Fibers:它们是否比迭代器更快,人们是否使用过它们?(Fibers in C#: are they faster than iterators, and have people used them?)
    问题 因此,我与一位同事讨论了 Fiber 的问题,并翻出了 2003 年的这篇论文,该论文描述了使用 Fiber API 在 C# 中实现协程。 本文中Yield的实现是针对 .NET 1.1 的,因此它早于 .NET 2.0 中出现的yield return语法。 乍一看,这里的实现可能更快,并且可以很好地跨多个 CPU 扩展。 有人用过吗? 回答1 我没用过,但我对这个主题很感兴趣。 这是在 C# 中使用循环调度程序很好的协程实现:http://www.bluebytesoftware.com/blog/PermaLink.aspx?guid=71235c5a-3753-4bab-bdb0-334ab439afaf 顺便说一句,引用维基百科的话说,“纤程描述的概念与协程本质上是相同的”。 据我所知,在 C# 中最接近协程(或纤程)的是迭代器。 实际上,它们非常接近协程。 Lippert 发布了几个关于迭代器的捕获。 希望它们中没有一个代表您需要的目的的严重问题。 回答2 我使用过基于产量的“协程”,我不得不说它们很麻烦。 问题是,当然,无论您想在何处使用它们,都必须使用 yield 语法。 不仅如此,除非您链接 yields(父级 yield 子级的 yields),否则您只能将协程嵌套一层深。 这完全破坏了协程的主要优势之一(全栈保存/恢复)。 我在 C#
  • 为什么 JavaScript 看起来比 C++ 快 4 倍?(Why does JavaScript appear to be 4 times faster than C++?)
    问题 很长一段时间以来,我一直认为 C++ 比 JavaScript 更快。 然而,今天我做了一个基准脚本来比较两种语言的浮点计算速度,结果令人惊叹! JavaScript 似乎比 C++ 快 4 倍! 我让两种语言在我的 i5-430M 笔记本电脑上做同样的工作,执行a = a + b 100000000 次。 C++ 大约需要 410 毫秒,而 JavaScript 只需要大约 120 毫秒。 我真的不知道为什么 JavaScript 在这种情况下运行得如此之快。 谁能解释一下? 我用于 JavaScript 的代码是(使用 Node.js 运行): (function() { var a = 3.1415926, b = 2.718; var i, j, d1, d2; for(j=0; j<10; j++) { d1 = new Date(); for(i=0; i<100000000; i++) { a = a + b; } d2 = new Date(); console.log("Time Cost:" + (d2.getTime() - d1.getTime()) + "ms"); } console.log("a = " + a); })(); 而 C++ 的代码(由 g++ 编译)是: #include <stdio.h> #include <ctime>
  • 为什么 C 这么快,为什么其他语言没有那么快或更快? [关闭](Why is C so fast, and why aren't other languages as fast or faster? [closed])
    问题 关闭。 这个问题是基于意见的。 它目前不接受答案。 想改善这个问题吗? 更新问题,以便通过编辑这篇文章用事实和引文来回答问题。 去年关闭。 改进这个问题 在收听 StackOverflow 播客时,人们不断提出“真正的程序员”用 C 编写的问题,而且 C 快得多,因为它“接近机器”。 将之前的断言留到另一篇文章中,C 有什么特别之处使它比其他语言更快? 或者换一种说法:是什么阻止其他语言能够编译成运行速度与 C 一样快的二进制文件? 回答1 C 没有什么特别之处。这就是它很快的原因之一。 支持垃圾收集、动态类型和其他使程序员更容易编写程序的工具的较新语言。 问题是,有额外的处理开销会降低应用程序的性能。 C 没有这些,这意味着没有开销,但这意味着程序员需要能够分配内存并释放它们以防止内存泄漏,并且必须处理变量的静态类型。 也就是说,许多语言和平台,例如 Java(带有 Java 虚拟机)和 .NET(带有公共语言运行时),这些年来随着诸如即时编译的出现而提高了性能字节码以实现更高的性能。 回答2 C 设计人员已经做出了权衡。 也就是说,他们决定将速度置于安全之上。 C不会 检查数组索引边界检查未初始化的变量值检查内存泄漏检查空指针取消引用 当您索引数组时,在 Java 中它需要在虚拟机中调用一些方法、边界检查和其他健全性检查。 这是有效的,绝对没问题,因为它增加了应有的安全性
  • 我是否应该始终使用Parallel.Foreach,因为必须有更多的线程才能加速所有工作?(Should I always use Parallel.Foreach because more threads MUST speed up everything?)
    问题 对每个普通的foreach使用parallel.foreach循环对您有意义吗? 我什么时候应该开始使用parallel.foreach,仅迭代1,000,000个项目? 回答1 不,对于每个foreach来说,这都是没有意义的。 原因如下: 您的代码实际上可能不是可并行化的。 例如,如果您将“到目前为止的结果”用于下一次迭代,则顺序很重要) 如果您正在汇总(例如,求和值),则可以使用Parallel.ForEach进行此操作,但您不应该盲目地这样做如果您的工作无论如何都能很快完成,那就没有任何好处,而且很可能会减慢速度 基本上,线程中的任何操作都不应盲目进行。 考虑一下在何处进行并行化实际上有意义。 哦,并衡量影响,以确保所带来的好处值得增加的复杂性。 (对于调试而言,这将变得更加困难。)TPL很棒,但它不是免费的午餐。 回答2 不,您绝对不应该这样做。 这里的重点不是真正的迭代次数,而是要完成的工作。 如果您的工作真的很简单,则并行执行1000000个委托将增加巨大的开销,并且很可能比传统的单线程解决方案要慢。 您可以通过对数据进行分区来解决此问题,因此您可以执行大量工作。 例如,考虑以下情况: Input = Enumerable.Range(1, Count).ToArray(); Result = new double[Count]; Parallel
  • C#任务、线程、Task类、Parall类
    使用并行处理执行多任务处理 在应用程序中执行多任务处理主要出于以下原因: 1.增强可响应性 长时间运行的操作可能涉及不需要处理器事件的任务。比如读写本地硬盘或通过网络收发数据。这个时候让CPU空转来等待任务完成没有意义。这个时候完全可以去干别的事情。 2.增强可伸缩性 如一个操作是CPU限制的,可有效利用可用的处理资源,并利用这些资源减少执行操作所需的事件来增强伸缩性. 在多核处理器之前的时候,单线程应用程序在一个更快的处理器上运行,速度就能变得更快.但在多核处理器的时代,在相同时钟频率的单核、双核或四核处理器上,单线程应用程序的速度是没有任何变化。 区别在于:在双核处理器上,一个内核处于空闲状态;四核处理器上,三个会处于空闲状态. 要最大化利用多核处理器,必须在写程序时就想好怎么利用多任务处理. … … 用.NET Framewordk实现多任务处理 多任务处理是指同时做多件事情的能力.理想情况下,多核处理器上运行的应用程序应执行跟处理内核数量一样多的并发任务,让每个内核都工作起来. 但是需要考虑以下几个问题: 1.如何将应用程序分解成一组并发操作? 2.如何安排一组操作在多个处理器上并发执行? 3.如何保证只执行处理器数量那么多的并发操作? 4.如一个操作阻塞(比如等待I/O操作完成),如何检测这种情况,并安排处理执行另一个操作,而不是在那傻等? 5
  • 将大型单体单线程应用程序转换为多线程架构的建议?(Advice for converting a large monolithic singlethreaded application to a multithreaded architecture?)
    问题 我公司的主要产品是大型单片 C++ 应用程序,用于科学数据处理和可视化。 它的代码库可以追溯到 12 或 13 年,虽然我们已经投入了升级和维护工作(使用 STL 和 Boost - 例如,当我加入大多数容器时,大多数容器都是自定义的 - 完全升级到 Unicode 和 2010 VCL 等)还有一个非常重要的问题:它是完全单线程的。 鉴于它是一个数据处理和可视化程序,这越来越成为一个障碍。 我是下一个版本的开发人员和项目经理,我们要解决这个问题,这在两个领域都将是一项艰巨的工作。 我正在寻求有关如何解决问题的具体、实用和架构建议。 程序的数据流可能是这样的: 一个窗口需要绘制数据在paint方法中,它会调用一个GetData方法,对于数百位的数据在一次paint操作中往往会调用数百次这将去计算或从文件或其他任何需要的东西中读取(通常是一个非常复杂的数据流 - 将其视为流经复杂图形的数据,其中的每个节点执行操作) 即,绘制消息处理程序将在处理完成时阻塞,如果数据尚未计算和缓存,这可能会很长一段时间。 有时这是几分钟。 执行冗长处理操作的程序的其他部分也会出现类似的路径 - 程序在整个时间(有时是数小时)内都没有响应。 我正在寻求有关如何改变这一点的建议。 实用的想法。 也许是这样的: 异步请求数据的设计模式? 存储大量对象以便线程可以安全地读写?
  • 为什么显式管理线程是一件坏事?(Why is the explicit management of threads a bad thing?)
    问题 在上一个问题中,我有点失礼了。 你看,我一直在阅读有关线程的文章,并认为它们是自奇异果冻以来最美味的东西。 想象一下我的困惑,当我读到这样的东西时: [T]hreads 是一件非常糟糕的事情。 或者,至少,线程的显式管理是一件坏事 和 跨线程更新 UI 通常表明您正在滥用线程。 由于每次有什么事情让我感到困惑时我都会杀死一只小狗,因此请考虑这是您恢复业力的机会...... 我应该如何使用线程? 回答1 学习线程的热情很棒; 不要误会我的意思。 相比之下,热衷于使用大量线程是我所谓的线程幸福病的症状。 刚刚了解线程功能的开发人员开始提出诸如“我可以在一个程序中创建多少个线程?”之类的问题。 这更像是一个英语专业的学生问“我可以在一个句子中使用多少个单词?” 对作家的典型建议是让你的句子简短而切题,而不是试图将尽可能多的单词和想法塞进一个句子中。 线程也是一样的; 正确的问题不是“我可以创造多少?” 而是“我怎样才能编写这个程序,使线程数成为完成工作所需的最少数量?” 线程解决了很多问题,这是真的,但它们也带来了巨大的问题: 多线程程序的性能分析通常极其困难且非常违反直觉。 我在大量多线程程序中看到过真实世界的例子,其中在不减慢任何其他功能或使用更多内存的情况下使函数更快,从而使系统的总吞吐量更小。 为什么? 因为线程往往就像市中心的街道。 想象一下,在不重新为红绿灯计时的情况下
  • LINQ语句比“ foreach”循环快吗?(Is a LINQ statement faster than a 'foreach' loop?)
    问题 我正在编写“网格渲染”管理器,并认为最好将所有使用同一着色器的网格进行分组,然后在我通过该着色器通道时进行渲染。 我当前正在使用一个foreach循环,但想知道使用LINQ是否可以提高性能? 回答1 为什么LINQ会更快? 它还在内部使用循环。 在大多数情况下,LINQ会变慢一些,因为它会带来开销。 如果您非常关心性能,请不要使用LINQ。 使用LINQ是因为您希望使用较短的可读性和可维护性更好的代码。 回答2 LINQ-to-Objects通常会增加一些边际开销(多个迭代器等)。 它仍然必须执行循环,并具有委托调用,并且通常将不得不做一些额外的解引用才能获取捕获的变量等。在大多数代码中,这实际上是不可检测的,并且比简单易懂的代码所提供的更多。 使用LINQ-to-SQL之类的其他LINQ提供程序,则由于查询可以在服务器上进行过滤,因此它应该比平面的foreach好得多,但是无论如何,您很可能都不会做完"select * from foo" ,所以不一定是公平的比较。 Re PLINQ; 并行性可以减少经过的时间,但是由于线程管理等开销,总的CPU时间通常会稍微增加。 回答3 LINQ现在比较慢,但是在某些时候可能会变快。 LINQ的优点是您不必关心它的工作方式。 如果想出一种新方法非常快,那么Microsoft的人员甚至可以在不告诉您的情况下实现该新方法
  • F#在科学计算中的表现(F# performance in scientific computing)
    问题 我很好奇 F# 性能与 C++ 性能相比如何? 我问了一个关于 Java 的类似问题,我得到的印象是 Java 不适合繁重的数字运算。 我已经读到 F# 应该具有更高的可扩展性和更高的性能,但是与 C++ 相比,这种实际性能如何? 关于当前实施的具体问题是: 它的浮点运算性能如何? 是否允许向量指令它对优化编译器有多友好? 它有多大的内存足迹? 它是否允许对内存局部性进行细粒度控制? 它是否具有分布式内存处理器的容量,例如 Cray? 它有哪些功能可能对涉及大量数字处理的计算科学感兴趣? 是否有实际的科学计算实现使用它? 谢谢 回答1 F# 以 .NET CLR 允许的速度执行浮点计算。 与 C# 或其他 .NET 语言没有太大区别。 F# 本身不允许向量指令,但如果您的 CLR 有这些 API,F# 使用它应该不会有问题。 参见例如 Mono。 据我所知,目前只有一个 F# 编译器,所以也许问题应该是“F# 编译器在优化方面有多好?”。 答案在任何情况下都是“可能与 C# 编译器一样好,目前可能会差一点”。 请注意,F# 与例如 C# 的不同之处在于它支持在编译时内联,这可能允许更高效的代码依赖于泛型。 F# 程序的内存占用与其他 .NET 语言的类似。 您对分配和垃圾收集的控制量与其他 .NET 语言相同。 我不知道对分布式内存的支持。 F#
  • 《深入理解计算机系统》(CSAPP)读书笔记 —— 第六章 存储器层次结构
      在计算机系统模型中,CPU执行指令,而存储器系统为CPU存放指令和数据。实际上,存储器系统是一个具有不同容量、成本和访问时间的存储设备的层次结构。   如果你的程序需要的数据是存储在CPU寄存器中,那么在指令的执行期间,在0个周期内就能访问到它们。如果存储在高速缓存中,需要4~75个周期。如果存储在主存中,需要上百个周期。而如果存储在磁盘上,需要大约几千万个周期!   计算机程序的一个基本属性称为局部性。具有良好局部性的程序倾向于一次又一次地访问相同的数据项集合,或是倾向于访问邻近的数据项集合。具有良好局部性的程序比局部性差的程序更多地倾向于从存储器层次结构中较高层次处访问数据项,因此运行得更快。文章目录存储技术局部性存储器层次结构高速缓存存储器编写高速缓存友好的代码总结随机访问存储器存储技术随机访问存储器  随机访问存储器( Random-Access Memory,RAM)分为两类:静态的和动态的。静态RAM(SRAM)比动态RAM(DRAM)更快,但也贵得多。SRAM用来作为高速缓存存储器。DRAM用来作为主存以及图形系统的帧缓冲区。静态RAM  SRAM将每个位存储在一个双稳态的( bistable)存储器单元里。每个单元是用一个六晶体管电路来实现的。这个电路有这样一个属性,它可以无限期地保持在两个不同的电压配置( configuration)或状态( state)之¸
  • 多线程——更快的方式?(Multi-threading — a faster way?)
    问题 我有一个类,在某个字段上有一个 getter getInt()和一个 setter setInt() ,比如说 field Integer Int; 一个类的对象,比如SomeClass 。 这里的setInt()是同步的——而getInt()不是。 我正在从多个线程中更新Int的值。 每个线程都获取值Int ,并对其进行适当设置。 线程不以任何方式共享任何其他资源。 每个线程中执行的代码如下。 public void update(SomeClass c) { while (<condition-1>) // the conditions here and the calculation of // k below dont have anything to do // with the members of c if (<condition-2>) { // calculate k here synchronized (c) { c.setInt(c.getInt()+k); // System.out.println("in "+this.toString()); } } } run()方法只是对通过传递给它的参数从构造函数内部更新的成员调用上述方法: public void run() { update(c); } 当我在大序列上运行它时,线程不会交错太多—