草庐IT

转到 channel : How to make this non-blocking?

coder 2023-06-28 原文

我有一个脚本,它从数据库中选择一些数据并将其发送到一个 channel 以供多个 goroutine 处理,然后将结果发送回主线程以在数据库中更新。

但是,它在将数据发送到第一个 channel 时挂起(可能阻塞)。

channel 是在全局范围内创建的:

var chin = make(chan in)
var chout = make(chan out)

inout 都是结构

首先启动 goroutines:

for i:=0; i<5; i++ {
     go worker()
}

然后加载 channel 的代码是:

        if verbose {
            fmt.Println(`Getting nextbatch2 and sending to workers`)
        }

        rows, err = nextbatch2.Query()
        if err != nil {
            panic(err)
        }

        var numtodo int
        for rows.Next() {
            err = rows.Scan(&id, &data)
            if err != nil {
                rows.Close()
                panic(err)
            }

            // Start
            var vin in
            vin.id = id
            vin.data = data
            chin <- vin
            numtodo++
        }
        rows.Close()

紧接着:

        if verbose {
            fmt.Println(`Processing out channel from workers`)
        }

        for res := range chout {
            update5.Exec(res.data, res.id)
            if numtodo--; numtodo == 0 {
                break
            }
        }

并且在后台运行着多个worker() goroutines:

func worker() {
      for res := range chin {
            var v out
            v.id = res.id
            v.data = process(res.data)
            chout <- v
      }
}

此代码在打印获取 nextbatch2 并发送给工作人员 后挂起。它永远不会到达 Processing out channel from workers。所以它卡在 rows.Next() 循环内的某个地方,为此我无法弄清楚原因,因为 chin channel 应该是非阻塞的 - 即使worker() goroutines 没有处理它应该至少完成那个循环。

有什么想法吗?

编辑:

通过在 rows.Next() 循环末尾添加 fmt.Println("on", numtodo) 我可以看到它在 5 之后阻塞,我不明白,因为它应该是非阻塞的,对吧?

编辑 2:

通过将 channel 更改为 make(chan in/out, 100),它现在将在 105 之后阻塞。

最佳答案

Receivers always block until there is data to receive. If the channel is unbuffered, the sender blocks until the receiver has received the value.

https://golang.org/doc/effective_go.html#channels

因此您可以将您的消费者代码重写为:

go func(){
    for res := range chout {
        update5.Exec(res.data, res.id)
    }
}()

您还需要 close(chin)close(chout) 才能正确使用 range 语句。

关于转到 channel : How to make this non-blocking?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29984040/

有关转到 channel : How to make this non-blocking?的更多相关文章

  1. 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

  2. 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

  3. 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

  4. 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

  5. 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

  6. ruby - 具有两个参数的 block - 2

    我从用户Hirolau那里找到了这段代码:defsum_to_n?(a,n)a.combination(2).find{|x,y|x+y==n}enda=[1,2,3,4,5]sum_to_n?(a,9)#=>[4,5]sum_to_n?(a,11)#=>nil我如何知道何时可以将两个参数发送到预定义方法(如find)?我不清楚,因为有时它不起作用。这是重新定义的东西吗? 最佳答案 如果您查看Enumerable#find的文档,您会发现它只接受一个block参数。您可以将它发送两次的原因是因为Ruby可以方便地让您根据它的“并行赋

  7. ruby - 在参数为 `yield self` 的方法中使用 `&block` 和在没有参数 `yield self` 的方法中使用 `&block` 有什么区别吗? - 2

    我明白了defa(&block)block.call(self)end和defa()yieldselfend导致相同的结果,如果我假设有这样一个blocka{}。我的问题是-因为我偶然发现了一些这样的代码,它是否有任何区别或者是否有任何优势(如果我不使用变量/引用block):defa(&block)yieldselfend这是一个我不理解&block用法的具体案例:defrule(code,name,&block)@rules=[]if@rules.nil?@rules 最佳答案 我能想到的唯一优点就是自省(introspecti

  8. ruby-on-rails - 连接字符串时如何在 <%=%> block 内输出 html_safe? - 2

    考虑一下:现在这些情况:#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2我需要用其他字符串输出URL。我如何保证&符号不会被转义?由于我无法控制的原因,我无法发送&。求助!把我的头发拉到这里:\编辑:为了澄清,我实际上有一个像这样的数组:@images=[{:id=>"fooid",:url=>"http://

  9. ruby - 从 sinatra 中的 before do block 返回不同的值 - 2

    有没有办法在sinatra的beforedoblock中停止执行并返回不同的值?beforedo#codeishere#Iwouldliketo'return"Message"'#Iwouldlike"/home"tonotgetcalled.end//restofthecodeget'/home'doend 最佳答案 beforedohalt401,{'Content-Type'=>'text/plain'},'Message!'end如果你愿意,你可以只指定状态,这里有状态、标题和正文的例子

  10. ruby - 为什么 return 关键字会导致我的 'if block' 出现问题? - 2

    下面的代码工作正常:person={:a=>:A,:b=>:B,:c=>:C}berson={:a=>:A1,:b=>:B1,:c=>:C1}kerson=person.merge(berson)do|key,oldv,newv|ifkey==:aoldvelsifkey==:bnewvelsekeyendendputskerson.inspect但是如果我在“ifblock”中添加return,我会得到一个错误:person={:a=>:A,:b=>:B,:c=>:C}berson={:a=>:A1,:b=>:B1,:c=>:C1}kerson=person.merge(berson

随机推荐