go版本go1.11.2 darwin/amd64
我有以下代码示例,是为 SO 演示目的而创建的:
package main
import (
...
)
type T struct {
ctx context.Context
ch1 chan string
}
func New(ctx context.Context) *T {
t := &T{ctx: ctx}
go t.run(2)
return t
}
func (t *T) run(workers int) {
t.ch1 = make(chan string)
done := make(chan struct{})
go func() {
<-t.ctx.Done()
close(done)
close(t.ch1)
}()
for i := 0; i < workers; i++ {
go func() {
for {
select {
case <-done:
return
case m, ok := <-t.ch1:
if ok {
t.process(done, m)
}
}
}
}()
}
}
func (t *T) process(done <-chan struct{}, s string) {
select {
case <-done:
return
default:
log.Printf("processing %s", s)
time.Sleep(time.Millisecond * 200)
}
}
func (t *T) Read() <-chan string {
return t.ch1
}
func (t *T) Write(s string) error {
select {
case <-t.ctx.Done():
return errors.New("consumer is closed today")
case t.ch1 <- s:
return nil
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
t := New(ctx)
go func() {
for m := range t.Read() {
log.Printf("got %s", m)
}
<-ctx.Done()
}()
for i := 0; i < 10; i++ {
t.Write(strconv.Itoa(i))
}
cancel()
}
当我使用竞争检测器构建并运行它时,它会抛出以下数据竞争:
go build -race ./test/ && ./test
==================
WARNING: DATA RACE
Read at 0x00c0000b6030 by goroutine 7:
main.main.func1()
/redacted/test/app.go:60 +0x42
Previous write at 0x00c0000b6030 by goroutine 6:
main.(*T).run()
/redacted/test/app.go:24 +0x6a
Goroutine 7 (running) created at:
main.main()
/redacted/test/app.go:76 +0xbc
Goroutine 6 (running) created at:
main.New()
/redacted/test/app.go:18 +0xcd
main.main()
/redacted/test/app.go:74 +0x86
==================
==================
WARNING: DATA RACE
Read at 0x00c0000b6030 by main goroutine:
main.(*T).Write()
/redacted/test/app.go:67 +0x8a
main.main()
/redacted/test/app.go:84 +0xdc
Previous write at 0x00c0000b6030 by goroutine 6:
main.(*T).run()
/redacted/test/app.go:24 +0x6a
Goroutine 6 (running) created at:
main.New()
/redacted/test/app.go:18 +0xcd
main.main()
/redacted/test/app.go:74 +0x86
==================
2019/01/20 10:48:51 got 0
2019/01/20 10:48:51 got 3
2019/01/20 10:48:51 processing 1
2019/01/20 10:48:51 processing 2
2019/01/20 10:48:51 got 4
2019/01/20 10:48:51 got 5
2019/01/20 10:48:51 got 6
2019/01/20 10:48:51 got 7
2019/01/20 10:48:51 got 8
2019/01/20 10:48:51 got 9
Found 2 data race(s)
我遇到的问题是,我似乎无法找到一种方法让用户在 channel 中输入内容,而不暴露任何写入 channel ,没有竞争。这怎么可能?有没有我缺少的更好的模式?
最佳答案
我建议进行以下更改:
New 中的 ch1 以避免在多个 goroutine 中读取和写入 t.ch1 的竞争Write 的调用完成后关闭ch1,以避免“在已关闭的 channel 上发送” panic sync.WaitGroup 在写入所有值后等待所有处理 goroutine 完成(这样程序不会在处理完成之前退出)将这些变化结合在一起,它看起来是这样的:
package main
import (
"log"
"strconv"
"sync"
"time"
)
type T struct {
// ch1 receives the values to process
ch1 chan string
// wg is used to wait for the workers to stop
wg sync.WaitGroup
}
func New() *T {
t := &T{
ch1: make(chan string),
}
go t.run(2)
return t
}
func (t *T) run(workers int) {
// add the workers to the WaitGroup
t.wg.Add(workers)
for i := 0; i < workers; i++ {
go func() {
// process values from the channel until it closes
// and then signal to the WaitGroup that we're done
defer t.wg.Done()
for m := range t.ch1 {
t.process(m)
}
}()
}
}
// Stop is called after we're done calling Write and we want to stop the
// processing once all values have been processed
func (t *T) Stop() {
// close t.ch1 so that the workers know to stop processing
close(t.ch1)
// wait for the workers to all finish before returning
t.wg.Wait()
}
func (t *T) process(s string) {
log.Printf("processing %s", s)
time.Sleep(time.Millisecond * 200)
}
func (t *T) Write(s string) {
t.ch1 <- s
}
func main() {
// start the main loop
t := New()
// write 10 values
for i := 0; i < 10; i++ {
t.Write(strconv.Itoa(i))
}
// stop the loop, which will wait for processing to finish before returning
t.Stop()
}
关于go - 发送到 channel 时避免竞争条件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54279262/
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano
我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_
我的Gallery模型中有以下查询:media_items.includes(:photo,:video).rank(:position_in_gallery)我的图库模型有_许多媒体项,每个都有一个照片或视频关联。到目前为止,一切正常。它返回所有media_items包括它们的photo或video关联,由media_item的position_in_gallery属性排序。但是我现在需要将此查询返回的照片限制为仅具有is_processing属性的照片,即nil。是否可以进行相同的查询,但条件是返回的照片等同于:.where(photo:'photo.is_processingIS
除了可访问性标准不鼓励使用这一事实指向当前页面的链接,我应该怎么做重构以下View代码?#navigation%ul.tabbed-ifcurrent_page?(new_profile_path)%li{:class=>"current_page_item"}=link_tot("new_profile"),new_profile_path-else%li=link_tot("new_profile"),new_profile_path-ifcurrent_page?(profiles_path)%li{:class=>"current_page_item"}=link_tot("p
有谁知道在Heroku的Bamboo堆栈上启动并运行使用DataMapper的Sinatra应用程序所需的魔法咒语?Bamboo堆栈不包含任何预安装的系统gem,无论我尝试使用何种gem组合,我都会不断收到此错误:undefinedmethod`auto_upgrade!'forDataMapper:Module(NoMethodError)这是我的.gems文件中的内容:sinatrapgdatamapperdo_postgresdm-postgres-adapter这些是我将应用程序推送到Heroku时安装的依赖项:----->Herokureceivingpush----->Si
我正在尝试按Rails相关模型中的字段进行排序。我研究的所有解决方案都没有解决如果相关模型被另一个参数过滤?元素模型classItem相关模型:classPriority我正在使用where子句检索项目:@items=Item.where('company_id=?andapproved=?',@company.id,true).all我需要按相关表格中的“位置”列进行排序。问题在于,在优先级模型中,一个项目可能会被多家公司列出。因此,这些职位取决于他们拥有的company_id。当我显示项目时,它是针对一个公司的,按公司内的职位排序。完成此任务的正确方法是什么?感谢您的帮助。PS-我
基本上,我只是试图在满足特定条件时停止程序运行其余行。unlessraw_information.firstputs"Noresultswerereturnedforthatquery"breakend然而,在程序运行之前我得到了这个错误:Invalidbreakcompileerror(SyntaxError)执行此操作的正确方法是什么? 最佳答案 abort("Noresultswerereturnedforthatquery")unlesscondition或unlessconditionabort("Noresultswer