假设一个 channel 有 10 个发送者和一个接收者。发送端函数需要一些时间来返回值。接收者只希望从 channel 中得到一个值(第一个接收到的值),其他 9 个值不用。接收方不需要等待剩下的 9 个值。这就是为什么我没有使用 sync.WaitGroup .
我使用了一个缓冲 channel ,所以当接收方只接收第一个数据时,缓冲 channel 中将有 9 个数据。我的问题是:
在没有接收方的情况下,是否可以保留数据打开的缓冲 channel ?下面的示例代码是一个简化的代码,但是如果程序是守护进程,它最终会被垃圾回收吗?
有没有更好的方法来处理这种情况?我尝试使用取消 channel 但失败了。我不确定 context适合这种情况。
示例代码:
package main
import (
"errors"
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
i, err := getRandomInt()
if err != nil {
fmt.Println(err)
} else {
fmt.Println(i)
}
fmt.Println("Waiting goroutines to be finished...")
time.Sleep(2 * time.Second)
}
func getRandomInt() (int, error) {
ch := make(chan int, 10)
// 10 senders
for i := 0; i < 10; i++ {
go func(i int) {
defer fmt.Printf("Goroutine #%d finished\n", i)
fmt.Printf("Goroutine #%d started\n", i)
data := heavyJob()
ch <- data
fmt.Printf("Goroutine #%d sent data %d to ch\n", i, data)
return
}(i)
}
// 1 receiver
timeout := time.After(2000 * time.Millisecond)
for {
select {
case value := <-ch:
// uses only the value received first, the rest are discarded
return value, nil
case <-timeout:
return -1, errors.New("Timeout")
}
}
}
// takes 1900~2900ms to finish
func heavyJob() int {
r := rand.Intn(1000)
time.Sleep(time.Duration(r+1900) * time.Millisecond)
return r
}
最佳答案
回答主要问题:
本质上,您是在工作人员数量和缓冲 channel 的大小之间创建一个隐式耦合。更改这两个数字中的一个,就会出现死锁/中断! (附带说明一下,缓冲 channel 通常适用于消费者和生产者以相同速率工作但输出不稳定的情况。它是尖峰的,缓冲平滑了波峰和波谷。)
考虑到这一点,我建议最好明确管理您不想要所有值的事实。
这是 getRandomInt() 函数的更新版本。请注意在顶部使用 defer 的上下文取消设置,以及在发送时使用 select 语句。
func getRandomInt() (int, error) {
ctx := context.Background() // creates a fresh, empty context
ctx, cancel := context.WithCancel(ctx)
defer cancel() // cancels the context when getRandomInt() returns
ch := make(chan int)
// 10 senders
for i := 0; i < 10; i++ {
go func(i int) {
defer fmt.Printf("Goroutine #%d finished\n", i)
fmt.Printf("Goroutine #%d started\n", i)
data := heavyJob()
// this select statement wil block until either this goroutine
// is the first to send, or the context is cancelled. In which case
// another routine has already sent and it can discard it's values.
select {
case ch <- data:
fmt.Printf("Goroutine #%d sent data %d to ch\n", i, data)
case <-ctx.Done():
fmt.Printf("Goroutine #%d did not send, context is cancelled, would have sent data %d to ch\n", i, data)
}
}(i)
}
// 1 receiver
timeout := time.After(2000 * time.Millisecond)
select {
case value := <-ch:
// uses only the value received first, the rest are discarded
return value, nil
case <-timeout:
return -1, errors.New("Timeout")
}
}
设置带有取消的上下文意味着一旦调用 cancel() 函数,上下文就会变为“完成”。这是一种告诉所有发送者 goroutines 不要费心等待发送的方法。
发送时,select 语句阻塞,直到上下文被 cancel() 函数取消;或者接收方方法读取第一个值。
我还从 channel 中删除了缓冲,因为不再需要它了。
关于go - 在没有接收方的情况下,是否可以保留数据打开的缓冲 channel ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50616147/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html
我有一个奇怪的问题:我在rvm上安装了rubyonrails。一切正常,我可以创建项目。但是在我输入“railsnew”时重新启动后,我有“程序'rails'当前未安装。”。SystemUbuntu12.04ruby-v"1.9.3p194"gemlistactionmailer(3.2.5)actionpack(3.2.5)activemodel(3.2.5)activerecord(3.2.5)activeresource(3.2.5)activesupport(3.2.5)arel(3.0.2)builder(3.0.0)bundler(1.1.4)coffee-rails(
这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的
我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法
我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI