草庐IT

c++ - 英特尔线程构建 block 并发队列 : Using pop() over pop_if_present()

coder 2024-02-20 原文

pop() 相比,使用阻塞调用有什么区别,

while(pop_if_present(...)) 

哪个应该优先于另一个?为什么?

我希望更深入地了解在 while(pop_if_present(...)) 情况下轮询自己与让系统为您完成轮询之间的权衡。这是一个很普遍的主题。例如,使用 boost::asio 我可以执行 myIO.run() 来阻止或执行以下操作:

while(1) 
{
myIO.poll()
}

一个可能的解释是调用 while(pop_if_present(...)) 的线程将保持忙碌,所以这很糟糕。但是某人或某物必须轮询异步事件。当它委托(delegate)给操作系统或库时,为什么以及如何能更便宜?是因为操作系统或库在轮询方面很聪明,例如进行指数退避吗?

最佳答案

Intel的TBB库是开源的,所以我看了看...

看起来 pop_if_present() 本质上是检查队列是否为空,如果为空则立即返回。如果不是,它会尝试获取队列顶部的元素(这可能会失败,因为另一个线程可能已经出现并接受了它)。如果未命中,它会在再次检查之前执行“atomic_backoff”暂停。 atomic_backoff 将简单地旋转它被调用的前几次(每次将其旋转循环计数加倍),但在一定数量的暂停后,它只会屈服于操作系统调度程序而不是根据假设进行旋转因为它已经等待了一段时间,所以它也可以做得很好。

对于普通的 pop() 函数,如果队列中没有任何内容,将执行 atomic_backoff 等待,直到队列中有内容。

请注意,至少有 2 件有趣的事情(对我来说):

  • pop() 函数执行自旋等待(直到某个点)以等待某些内容出现在队列中;它不会屈服于操作系统,除非它必须等待很短的时间。因此,正如您可能预料的那样,没有太多理由让您自己调用 pop_if_present() 除非您在调用 pop_if_present() 之间有其他事情要做p>

  • pop() 确实屈服于操作系统时,它通过简单地放弃它的时间片来做到这一点。它不会阻塞同步对象上的线程,当一个项目被放置在队列中时可以发出信号 - 它似乎进入休眠/轮询周期以检查队列中是否有要弹出的东西。这让我有点吃惊。

对这个分析持保留态度...我用于此分析的源代码可能有点旧(它实际上来自 concurrent_queue_v2.h 和 .cpp),因为最近的 concurrent_queue 有不同的 API - 没有 pop()pop_if_present(),只是最新的 class concurrent_queue 接口(interface)中的一个 try_pop() 函数。旧接口(interface)已移动(可能有所更改)到 concurrent_bounded_queue 类。似乎可以在构建库时配置较新的 concurrent_queues 以使用 OS 同步对象而不是繁忙的等待和轮询。

关于c++ - 英特尔线程构建 block 并发队列 : Using pop() over pop_if_present(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2285375/

有关c++ - 英特尔线程构建 block 并发队列 : Using pop() over pop_if_present()的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  3. ruby-on-rails - Enumerator.new 如何处理已通过的 block ? - 2

    我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m

  4. ruby-on-rails - `a ||= b` 和 `a = b if a.nil 之间的区别? - 2

    我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行

  5. ruby - ruby 中有 each_if 吗? - 2

    假设我在Ruby中有这个each循环。@list.each{|i|putsiifi>10breakend}我想循环遍历列表直到满足条件。这让我感到“不像Ruby”,因为我是Ruby的新手,是否有Ruby方法可以做到这一点? 最佳答案 您可以使用Enumerable#detect或Enumerable#take_while,取决于您想要的结果。@list.detect{|i|putsii>10}#Returnsthefirstelementgreaterthan10,ornil.正如其他人所指出的,更好的风格是先进行子选择,然后再对其

  6. ruby - 在匿名 block 中产生 - 2

    我没有理解以下行为(另请参阅inthisSOthread):defdef_testputs'def_test.in'yieldifblock_given?puts'def_test.out'enddef_testdoputs'def_testok'endblock_test=procdo|&block|puts'block_test.in'block.callifblockputs'block_test.out'endblock_test.calldoputs'block_test'endproc_test=procdoputs'proc_test.in'yieldifblock_gi

  7. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  8. ruby - Ruby 中的单 block AES 解密 - 2

    我需要尝试一些AES片段。我有一些密文c和一个keyk。密文已使用AES-CBC加密,并在前面加上IV。不存在填充,纯文本的长度是16的倍数。所以我这样做:aes=OpenSSL::Cipher::Cipher.new("AES-128-CCB")aes.decryptaes.key=kaes.iv=c[0..15]aes.update(c[16..63])+aes.final它工作得很好。现在我需要手动执行CBC模式,所以我需要单个block的“普通”AES解密。我正在尝试这个:aes=OpenSSL::Cipher::Cipher.new("AES-128-ECB")aes.dec

  9. ruby-on-rails - 无法在 Rails 助手中捕获 block 的输出 - 2

    我在使用自定义RailsFormBuilder时遇到了问题,从昨天晚上开始我就发疯了。基本上我想对我的构建器方法之一有一个可选block,以便我可以在我的主要content_tag中显示其他内容。:defform_field(method,&block)content_tag(:div,class:'field')doconcatlabel(method,"Label#{method}")concattext_field(method)capture(&block)ifblock_given?endend当我在我的一个Slim模板中调用该方法时,如下所示:=f.form_field:e

  10. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

随机推荐