草庐IT

Java lambda、无状态 lambda 和并行执行

coder 2024-03-18 原文

在尝试学习 Java lambda 时,我看到了一篇文章(在下面列出),其中在关于流 API 的局限性的部分中,他指出:“有状态的 lambda 在顺序执行时通常不是问题,但是当流执行是并行的,它会中断”。然后,他将这段代码作为执行顺序问题的示例:

List<String> ss = ...;
List<String> result = ...;

Stream<String> stream = ss.stream();

stream.map(s -> {
    synchronized (result) {
      if (result.size() < 10) {
        result.add(s);
      }
    }
})
.forEach(e -> { });

我可以看出如果它是并行化的,这将如何是不确定的,但我看不到的是你将如何使用无状态 lambda 来解决这个问题——将东西添加到一个以并行方式列出。一个六岁的戴帽子的 child 可以理解的例子,也许是用 C# 写的,将不胜感激。

原始文章链接 http://blog.hartveld.com/2013/03/jdk-8-33-stream-api.html

最佳答案

我知道你的问题在暗示什么,我会尽力解释。

考虑一个包含 8 个元素的输入列表:

[1, 2, 3, 4, 5, 6, 7, 8]

并假设流会以下列方式将其并行化,但实际上并不会,并行化的确切过程很难理解。
但现在,假设他们将大小除以二,直到剩下两个元素。

分支部门看起来像这样:

  1. 第一师:

    [1, 2, 3, 4]
    [5, 6, 7, 8]

  2. 第二师:

    [1, 2]
    [3, 4]
    [5, 6]
    [7, 8]

现在我们有四个 block (在我们的理论中)将由四个不同的线程处理,它们彼此不知道。
这确实可以通过同步一些外部资源来解决,但是你失去了并行化的好处,所以我们需要假设我们不同步,当我们不同步时,其他线程将看不到任何其他线程有什么完成,所以我们的结果将是垃圾。

现在进入您询问无状态的问题部分,然后如何正确地并行处理它?如何将以正确顺序并行处理的元素添加到列表中?

首先假设一个简单的映射函数,您在其中使用 lambda i -> i + 10 进行映射。 , 然后用 System.out::println 打印出来在 foreach 中。

现在,在第二次划分之后,将发生以下情况:

[1, 2] -> [11, 12] -> { System.out.println(11); System.println(12); }
[3, 4] -> [13, 14] -> { System.out.println(13); System.println(14); }
[5, 6] -> [15, 16] -> { System.out.println(15); System.println(16); }
[7, 8] -> [17, 18] -> { System.out.println(17); System.println(18); }

除了由同一线程处理的所有元素(内部状态,不依赖)按顺序处理外,无法保证顺序。

如果你想按顺序处理它们,那么你需要使用forEachOrdered ,这将确保所有线程以正确的顺序运行,并且您不会因此失去太多并行化优势,因为它仅适用于结束状态。

要了解如何将并行化的项目添加到列表中,请使用 Collectors.toList() 查看这个,它提供了以下方法:

  • 创建新列表。
  • 向列表中添加一个值。
  • 合并两个列表。

现在在第二次划分之后会发生以下情况:

对于每四个线程,它将执行以下操作(此处仅显示一个线程):

  1. 我们有 [1, 2] .
  2. 我们将其映射到 [11, 12] .
  3. 我们创建一个空的 List<Integer> .
  4. 我们添加 11到列表。
  5. 我们添加 12到列表。

现在所有线程都完成了这个,我们有四个包含两个元素的列表。

现在以下合并按指定顺序发生:

  1. [11, 12] ++ [13, 14] = [11, 12, 13, 14]
  2. [15, 16] ++ [17, 18] = [15, 16, 17, 18]
  3. 最后 [11, 12, 13, 14] ++ [15, 16, 17, 18] = [11, 12, 13, 14, 15, 16, 17, 18]

因此结果列表是有序的并且映射是并行完成的。现在您应该也能明白为什么并行化需要更高的最小值,因为只有两个项目,否则创建新列表和合并的成本太高。

我希望您现在明白为什么流操作应该无状态才能获得并行化的全部好处。

关于Java lambda、无状态 lambda 和并行执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23410408/

有关Java lambda、无状态 lambda 和并行执行的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby-openid:执行发现时未设置@socket - 2

    我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass

  3. ruby - Chef 执行非顺序配方 - 2

    我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul

  4. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  5. ruby - 为什么 Ruby 的 each 迭代器先执行? - 2

    我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试

  6. ruby - 字符串文字中的转义状态作为 `String#tr` 的参数 - 2

    对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一

  7. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  8. ruby - 检查是否通过 require 执行或导入了 Ruby 程序 - 2

    如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby​​文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否

  9. postman——集合——执行集合——测试脚本——pm对象简单示例02 - 2

    //1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json

  10. ruby-on-rails - rbenv:从 RVM 移动到 rbenv 后,在 Jenkins 执行 shell 中找不到命令 - 2

    我从Ubuntu服务器上的RVM转移到rbenv。当我使用RVM时,使用bundle没有问题。转移到rbenv后,我在Jenkins的执行shell中收到“找不到命令”错误。我内爆并删除了RVM,并从~/.bashrc'中删除了所有与RVM相关的行。使用后我仍然收到此错误:rvmimploderm~/.rvm-rfrm~/.rvmrcgeminstallbundlerecho'exportPATH="$HOME/.rbenv/bin:$PATH"'>>~/.bashrcecho'eval"$(rbenvinit-)"'>>~/.bashrc.~/.bashrcrbenvversions

随机推荐