Parallel.For 与 BigInteger 计算输出不同于 For 循环

2024-02-05

我有以下循环运行从 base95 到 base10 的转换。我正在处理几千位数字,因此需要 BigIntegers。inst是base95字符串。

Parallel.For(0, inst.Length, x => 
     {
        result += BigInteger.Pow(95, x) * (inst[x] - 32);
     });

如果我使用大约 200 个字符或更少的 Base95 字符串,它工作得非常好,并且输出与正常的结果相同的结果for循环会。

然而,一旦我开始增加 base95 字符串的大小,并行的输出就会被抛弃。我需要使用包含 1500 多个字符、甚至最多 30000 个字符的 Base95 字符串。for循环可以很好地计算结果。

什么可能导致这个问题?有没有比这更好的方法Parallel.For循环仍然比for loop?


它只是不是线程安全的。至于为什么它不会被较小的字符串破坏,我不确定。可能TPL只是认为工作负载不值得额外的线程。虽然,我确实验证了您的结果,但它确实会因较大的字符串而产生不一致的结果。

唯一的解决方案是使其线程安全。一种廉价且令人讨厌的方法是使用lock...如果您可以使用另一种线程安全方法,例如但是,它不适用于BigInteger.

BigInteger result = 0;
object sync = new object();

Parallel.For(
   0,
   inst.Length,
   x =>
      {
         var temp = BigInteger.Pow(95, x) * (inst[x] - 32);
         lock (sync)
            result += temp;
      });

它的所有锁定并不完美,但仍然比普通的快for在我的电脑上循环播放

另一种方法是使用 for 重载,这样每个线程只锁定一次。

Parallel.For(
   0,
   inst.Length,
   () => new BigInteger(0),
   (x, state, subTotal) => subTotal + BigInteger.Pow(95, x) * (inst[x] - 32),
   integer =>
      {
         lock (sync)
            result += integer;
      });

基准测试

所以我很无聊,这是你的基准

每次测试运行 50 次,GC.Collect and GC.WaitForPendingFinalizers在每次测试之前运行以提供更清晰的结果。所有结果都经过相互测试以证明它们是准确的。Scale表示根据您的问题的字符串的大小

Setup

----------------------------------------------------------------------------
Mode             : Release (64Bit)
Test Framework   : .NET Framework 4.7.1 (CLR 4.0.30319.42000)
----------------------------------------------------------------------------
Operating System : Microsoft Windows 10 Pro
Version          : 10.0.17134
----------------------------------------------------------------------------
CPU Name         : Intel(R) Core(TM) i7-3770K CPU @ 3.50GHz
Description      : Intel64 Family 6 Model 58 Stepping 9
Cores (Threads)  : 4 (8)      : Architecture  : x64
Clock Speed      : 3901 MHz   : Bus Speed     : 100 MHz
L2Cache          : 1 MB       : L3Cache       : 8 MB
----------------------------------------------------------------------------

Results

--- Random characters -----------------------------------------------------------------
| Value          |    Average |    Fastest |    Cycles | Garbage | Test |        Gain |
--- Scale 10 ----------------------------------------------------------- Time 0.259 ---
| for            |   5.442 µs |   4.968 µs |  21.794 K | 0.000 B | Base |      0.00 % |
| ParallelResult |  32.451 µs |  30.397 µs | 116.808 K | 0.000 B | Pass |   -496.25 % |
| ParallelLock   |  35.551 µs |  32.443 µs | 127.966 K | 0.000 B | Pass |   -553.22 % |
| AsParallel     | 141.457 µs | 118.959 µs | 398.676 K | 0.000 B | Pass | -2,499.13 % |
--- Scale 100 ---------------------------------------------------------- Time 0.298 ---
| ParallelResult |  93.261 µs |  80.085 µs | 329.450 K | 0.000 B | Pass |     11.36 % |
| ParallelLock   | 103.912 µs |  84.470 µs | 366.599 K | 0.000 B | Pass |      1.23 % |
| for            | 105.210 µs |  93.823 µs | 371.025 K | 0.000 B | Base |      0.00 % |
| AsParallel     | 183.538 µs | 159.002 µs | 488.534 K | 0.000 B | Pass |    -74.45 % |
--- Scale 1,000 -------------------------------------------------------- Time 4.191 ---
| AsParallel     |   5.701 ms |   4.932 ms |  15.479 M | 0.000 B | Pass |     65.83 % |
| ParallelResult |   6.510 ms |   5.701 ms |  18.166 M | 0.000 B | Pass |     60.98 % |
| ParallelLock   |   6.734 ms |   5.303 ms |  17.314 M | 0.000 B | Pass |     59.64 % |
| for            |  16.685 ms |  15.640 ms |  58.183 M | 0.000 B | Base |      0.00 % |
--- Scale 10,000 ------------------------------------------------------ Time 34.805 ---
| AsParallel     |    6.205 s |    4.767 s |  19.202 B | 0.000 B | Pass |     47.20 % |
| ParallelResult |    6.286 s |    5.891 s |  14.752 B | 0.000 B | Pass |     46.51 % |
| ParallelLock   |    6.290 s |    5.202 s |   9.982 B | 0.000 B | Pass |     46.48 % |
| for            |   11.752 s |   11.436 s |  41.136 B | 0.000 B | Base |      0.00 % |
---------------------------------------------------------------------------------------

并行锁

[Test("ParallelLock", "", true)]
public BigInteger Test1(string input, int scale)
{
   BigInteger result = 0;
   object sync = new object();

   Parallel.For(
      0,
      input.Length,
      x =>
         {
            var temp = BigInteger.Pow(95, x) * (input[x] - 32);
            lock (sync)
               result += temp;
         });

   return result;
}

并行结果

[Test("ParallelResult", "", false)]
public BigInteger Test2(string input, int scale)
{
   BigInteger result = 0;
   object sync = new object();
   Parallel.For(
      0,
      input.Length,
      () => new BigInteger(0),
      (x, state, subTotal) => subTotal + BigInteger.Pow(95, x) * (input[x] - 32),
      integer =>
         {
            lock (sync)
               result += integer;
         });
   return result;
}

作为并行投标人gdir https://stackoverflow.com/users/3563563/gdir

[Test("AsParallel", "", false)]
public BigInteger Test4(string input, int scale)
{
   return Enumerable.Range(0, input.Length)
                    .AsParallel()
                    .Aggregate(
                        new BigInteger(0),
                        (subtotal, x) => subtotal + BigInteger.Pow(95, x) * (input[x] - 32),
                        (total, thisThread) => total + thisThread,
                        (finalSum) => finalSum);;
}

for

[Test("for", "", false)]
public BigInteger Test3(string input, int scale)
{       
   BigInteger result = 0;
   for (int i = 0; i < input.Length; i++)
   {
      result += BigInteger.Pow(95, i) * (input[i] - 32);
   }
   return result;
}

Input

public static string StringOfChar(int scale)
{
   var list = Enumerable.Range(1, scale)
                        .Select(x => (char)(_rand.Next(32)+32))
                        .ToArray();
   return string.Join("", list);
} 

验证

private static bool Validation(BigInteger result, BigInteger baseLine)
{
   return result == baseLine;
}

Summary

并行会给你带来性能提升,理论上你可以锁定的越少越好,但是可能有很多因素导致结果如此。看来结果过载似乎工作得很好,但与较大的工作负载非常相似,我不太确定为什么。请注意,我没有使用并行选项,您也许可以根据您的解决方案对其进行更多调整

不管怎样,祝你好运

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

Parallel.For 与 BigInteger 计算输出不同于 For 循环 的相关文章

  • 为什么在连接两个字符串时 Python 比 C 更快?

    目前我想比较 Python 和 C 用来处理字符串的速度 我认为 C 应该比 Python 提供更好的性能 然而 我得到了完全相反的结果 这是 C 程序 include
  • 如何在多线程C++ 17程序中交换两个指针?

    我有两个指针 pA 和 pB 它们指向两个大的哈希映射对象 当pB指向的哈希图完全更新后 我想交换pB和pA 在C 17中 如何快速且线程安全地交换它们 原子 我是 c 17 的新手 2个指针的原子无等待交换可以通过以下方式实现 inclu
  • 如何捕获未发送到 stdout 的命令行文本?

    我在项目中使用 LAME 命令行 mp3 编码器 我希望能够看到某人正在使用什么版本 如果我只执行 LAME exe 而不带参数 我会得到 例如 C LAME gt LAME exe LAME 32 bits version 3 98 2
  • 代码 GetAsyncKeyState(VK_SHIFT) & 0x8000 中的这些数字是什么?它们是必不可少的吗?

    我试图在按下按键的简单动作中找到这些数字及其含义的任何逻辑解释 GetAsyncKeyState VK SHIFT 0x8000 可以使用哪些其他值来代替0x8000它们与按键有什么关系 GetAsyncKeyState 根据文档返回 如果
  • IdentityServer 4 对它的工作原理感到困惑

    我阅读和观看了很多有关 Identity Server 4 的内容 但我仍然对它有点困惑 因为似乎有很多移动部件 我现在明白这是一个单独的项目 它处理用户身份验证 我仍然不明白的是用户如何注册它 谁存储用户名 密码 我打算进行此设置 Rea
  • 查找进程的完整路径

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

    我正在使用 WCF 开发一组服务 该应用程序正在使用 Castle Windsor 进行依赖注入 我添加了一个IErrorHandler通过属性添加到服务的实现 到目前为止一切正常 这IErrorHandler对象 一个名为FaultHan
  • 当一组凭据下的计划任务启动的进程在另一组凭据下运行另一个程序时,Windows 是否有限制

    所以我有一个简单的例子 其中我有应用程序 A 它对用户 X 本地管理员 有一些硬编码的凭据 然后它使用硬编码的绝对路径启动带有这些凭据的应用程序 B A 和 B 以及 dotnet 控制台应用程序 但是它们不与控制台交互 只是将信息写入文件
  • File.AppendText 尝试写入错误的位置

    我有一个 C 控制台应用程序 它作为 Windows 任务计划程序中的计划任务运行 此控制台应用程序写入日志文件 该日志文件在调试模式下运行时会创建并写入应用程序文件夹本身内的文件 但是 当它在任务计划程序中运行时 它会抛出一个错误 指出访
  • 打破 ReadFile() 阻塞 - 命名管道 (Windows API)

    为了简化 这是一种命名管道服务器正在等待命名管道客户端写入管道的情况 使用 WriteFile 阻塞的 Windows API 是 ReadFile 服务器已创建启用阻塞的同步管道 无重叠 I O 客户端已连接 现在服务器正在等待一些数据
  • 在 NaN 情况下 to_string() 可以返回什么

    我使用 VS 2012 遇到了非常令人恼火的行为 有时我的浮点数是 NaN auto dbgHelp std to string myFloat dbgHelp最终包含5008角色 你不能发明这个东西 其中大部分为0 最终结果是 0 INF
  • 等待 IAsyncResult 函数直至完成

    我需要创建等待 IAsyncResult 方法完成的机制 我怎样才能做到这一点 IAsyncResult result contactGroupServices BeginDeleteContact contactToRemove Uri
  • 在屏幕上获取字符

    我浏览了 NCurses 函数列表 似乎找不到返回已打印在屏幕上的字符的函数 每个字符单元格中存储的字符是否有可访问的值 如果没有的话Windows终端有类似的功能吗 我想用它来替换屏幕上某个值的所有字符 例如 所有a s 具有不同的特征
  • 使 Guid 属性成为线程安全的

    我的一个类有一个 Guid 类型的属性 该属性可以由多个线程同时读写 我的印象是对 Guid 的读取和写入不是原子的 因此我应该锁定它们 我选择这样做 public Guid TestKey get lock testKeyLock ret
  • String.Empty 与 "" [重复]

    这个问题在这里已经有答案了 可能的重复 String Empty 和 有什么区别 https stackoverflow com questions 151472 what is the difference between string
  • 如何在richtextbox中使用多颜色[重复]

    这个问题在这里已经有答案了 我使用 C windows 窗体 并且有 richtextbox 我想将一些文本设置为红色 一些设置为绿色 一些设置为黑色 怎么办呢 附图片 System Windows Forms RichTextBox有一个
  • 我可以在“字节数”设置为零的情况下调用 memcpy() 和 memmove() 吗?

    当我实际上没有什么可以移动 复制的时候 我是否需要处理这些情况memmove memcpy 作为边缘情况 int numberOfBytes if numberOfBytes 0 memmove dest source numberOfBy
  • 为boost python编译的.so找不到模块

    我正在尝试将 C 代码包装到 python 中 只需一个类即可导出两个函数 我编译为map so 当我尝试时import map得到像噪音一样的错误 Traceback most recent call last File
  • Objective-C / C 给出枚举默认值

    我在某处读到过关于给枚举默认值的内容 如下所示 typedef enum MarketNavigationTypeNone 0 MarketNavigationTypeHeirachy 1 MarketNavigationTypeMarke
  • OpenCV SIFT 描述符关键点半径

    我正在深入研究OpenCV的SIFT描述符提取的实现 https github com Itseez opencv blob master modules nonfree src sift cpp 我发现了一些令人费解的代码来获取兴趣点邻域

随机推荐