【问题标题】:Comparing Boost.Fiber with Goroutines correct usability比较 Boost.Fiber 和 Goroutines 的正确可用性
【发布时间】:2020-03-27 08:38:03
【问题描述】:

早安,

嗯,我知道已经有一些关于 Boost.Fiber 和 Goroutines 比较的讨论。但是作为并发领域的新开发人员,我对差异和可用性感到很困惑。

所以目前,我正在做一些 Go 到 C++ 的迁移,我的一些障碍是使用 Channels 和 Goroutines,所以我对并发、Boost.Fiber 和 Goroutines 做了一些小阅读,并基于我对这个话题的理解。

package main

import (
"fmt"
"time"
)

const (
    timeout    = 0
    interrupt  = 1
    serverDone = 2
)

func runDurationTimer(d time.Duration, toStop chan int) {
    go func() {
        dSeconds := uint64(d.Seconds())
        if dSeconds == 0 {
            return
        }
        time.Sleep(d)
        toStop <- timeout
    }()
}

func clientWatchControlChannel(d time.Duration, toStop chan int) {
    go func() {
        time.Sleep(d)
        toStop <- serverDone
    }()
}

func main() {
    toStop := make(chan int, 1)
    d := 5 * time.Second
    runDurationTimer(d, toStop)
    clientWatchControlChannel(1 * time.Second, toStop)

    fmt.Println("Hello World \n")

    reason := <-toStop
    switch reason {
    case timeout:
        fmt.Println("Process done, duration: " + d.String() +".")
    case interrupt:
        fmt.Println("Process done, received interrupt signal.")
    case serverDone:
        fmt.Println("Process done, server terminated the session.")
    }
}

所以上面的代码是一个基本的成功和超时方案,当一个函数在一定时间内没有返回一个状态时,它就会超时。

对于实际场景中的clientWatchControlChannelSleep 将是需要返回某些内容并完成该过程的其他进程。基于硬编码值,整个程序返回"Process done, server terminated the session.",因为运行clientWatchControlChannel的持续时间是runDurationTimer中的超时值。

所以当我调试代码时,它运行了 2 个过程,所以我在 toStop &lt;- timeouttoStop &lt;- serverDone 处放置了一个断点,所以 runDurationTimer 运行然后休眠,然后等待完成它运行 clientWatchControlChannel 然后首先完成因为它的持续时间比runDurationTimer 短,在此之后,它不会回到runDurationTimer 并等待,它只是终止并为输出分配值。

根据我对 C++ 的理解,我编写了以下代码。

#include <boost/fiber/all.hpp>
#include <chrono>
#include <iostream>

typedef boost::fibers::unbuffered_channel<int> unbuffered_channel_t;

enum stop { timeout = 0, interrupt, serverDone };

void runDurationTimer(
    const std::chrono::duration<std::uint32_t, std::ratio<1, 1>> &d,
    unbuffered_channel_t &toStop) {
  boost::fibers::async([&]() {
    if (d.count() == 0) {
      return;
    }
    boost::this_fiber::sleep_for(d);
    toStop.push(timeout);
  });
}

void clientWatchChannel(
    const std::chrono::duration<std::uint32_t, std::ratio<1, 1>> &d,
    unbuffered_channel_t &toStop) {
  boost::fibers::async([&]() {
    boost::this_fiber::sleep_for(d);
    toStop.push(serverDone);
  });
}

int main() {
  unbuffered_channel_t chan;
  auto dTime = std::chrono::duration<std::uint32_t, std::ratio<1, 1>>(3);
  auto dWatch = std::chrono::duration<std::uint32_t, std::ratio<1, 1>>(1);

  runDurationTimer(dTime, chan);
  clientWatchChannel(dWatch, chan);

  std::cout << "Hello, World!\n";

  int i = 0;
  chan.pop(i);


  switch (i) {
  case timeout:
    std::cout << "Process done, duration: " << std::to_string(dTime.count())
              << ".";
    break;
  case interrupt:
    std::cout << "Process done, received interrupt signal.";
    break;
  case serverDone:
    std::cout << "Process done, server terminated the session.";
    break;
  default:
    break;
  }
  return 0;
}

因此,长话短说,一切在行为上几乎相同。同样,我调试了代码,在toStop.push(serverDone);toStop.push(timeout); 中放置了断点,所以与Go 相同,它先运行runDurationTimer,然后在等待它完成时clientWatchControlChannel 启动并运行toStop.push(serverDone);,但是区别不是终止,而是回到runDurationTimer 并运行toStop.push(timeout);。所以我认为这是我真正感到困惑的事情。然后chan.pop(i)返回serverDone

所以,我真的需要一些帮助来理解它是否正确,或者我应该继续使用 Boost.Fiber 进行 Go 迁移还是使用 Boost.Coroutines2。任何建议、反应和更正都非常感谢,我愿意从中学习。

我也对我的 C++ 表示歉意,一直停滞不前。 :)

谢谢。

【问题讨论】:

    标签: c++ boost goroutine boost-fiber


    【解决方案1】:

    你必须关闭频道

     #include <boost/fiber/all.hpp>
     #include <chrono>
     #include <iostream>
    
     typedef boost::fibers::unbuffered_channel<int> unbuffered_channel_t;
    
     enum stop { timeout = 0, interrupt, serverDone };
    
     void runDurationTimer(
         const std::chrono::duration<std::uint32_t, std::ratio<1, 1>> &d,
         unbuffered_channel_t &toStop) {
       boost::fibers::async([&]() {
         if (d.count() == 0) {
           return;
         }
         boost::this_fiber::sleep_for(d);
         // return value would indicate that the channel was closed
         // `timeout` will not be inserted into the channel
         toStop.push(timeout);
       });
     } 
    
     void clientWatchChannel(
         const std::chrono::duration<std::uint32_t, std::ratio<1, 1>> &d,
         unbuffered_channel_t &toStop) {
       boost::fibers::async([&]() {
         boost::this_fiber::sleep_for(d);
         toStop.push(serverDone);
         toStop.close();
       });
      } 
    
      int main() {
       unbuffered_channel_t chan; 
       auto dTime = std::chrono::duration<std::uint32_t, std::ratio<1, 1>>(3);
       auto dWatch = std::chrono::duration<std::uint32_t, std::ratio<1, 1>>(1);
    
       runDurationTimer(dTime, chan);
       clientWatchChannel(dWatch, chan);
    
       std::cout << "Hello, World!\n";
    
       int i = 0;
       chan.pop(i);         
    
       switch (i) {
       case timeout:
         std::cout << "Process done, duration: " << std::to_string(dTime.count())
                   << ".";
         break;
       case interrupt:
         std::cout << "Process done, received interrupt signal.";
         break;
       case serverDone:
         std::cout << "Process done, server terminated the session.";
         break;
       default:
         break;
       }
       std::cout << "\n";
       return 0;
      }
    

    你好,世界!

    处理完成,服务器终止会话。

    【讨论】:

    • 感谢您的回答,我同意应该在一个线程返回后关闭通道,但是如果您调试代码,则在clientWatchChannel完成后返回runDurationTimer,其中有一个Goroutine + 通道的不同行为。 GoroutineclientWatchChannel 完成后完成整个过程并且不等待 runDurationTimer
    • boost::fiber != Goroutine(boost.fiber 是用户级线程,具有类似 std::thread 的 API)我看不出为什么 clientWatchChannel() 生成的 Fiber 应该终止进程(没有胶水代码可以表明它)。
    猜你喜欢
    • 2022-01-15
    • 2023-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-28
    • 2015-03-26
    • 2016-06-29
    • 2011-12-13
    相关资源
    最近更新 更多