我是初学者 gopher,我为我正在从事的项目编写了一个事件监听器工作队列。
我已将其部署在临时服务器上。在触发大约 100 个事件后,监听器将在事件发布时停止调用。服务器也没有崩溃。
这是我的实现:
// Event struct
type Event struct {
Name string
Data interface{}
}
// Stream to publish events to
var stream = make(chan *Event, 100)
// Publish sends new event data to the stream by the event name
func Publish(name string, data interface{}) {
ev := &Event{name, data}
stream <- ev
}
// Handler provides the interface for all event handlers.
// The Work will be called with the event that it should process
type Handler interface {
Work(*Event)
}
type worker struct {
Handler
Listen chan *Event
Quit chan bool
}
// Stop shuts down the worker
func (w *worker) Stop() {
go func() {
w.Quit <- true
}()
}
// Queue of worker Listen channels
type workerQueue chan chan *Event
// registry of workers
var registry = make(map[string][]workerQueue)
// Register creates 20 workers, assigns them to a queue, and
// appends the resulting worker queue to an event on the handler registry
func Register(name string, handlers ...Handler) {
if _, ok := registry[name]; !ok {
registry[name] = make([]workerQueue, 0)
}
// Create workerQueues for each handler
for _, h := range handlers {
queue := make(workerQueue, numListeners)
// Create 20 workers
for i := 0; i < 20; i++ {
newWorker := worker{
Handler: h,
Listen: make(chan *Event),
Quit: make(chan bool),
}
go func() {
for {
select {
case ev := <-newWorker.Listen:
nl.Work(ev)
case <-newWorker.Quit:
return
}
}
}()
queue <- newWorker.Listen
}
registry[name] = append(registry[name], queue)
}
}
// Start begins listening for events on stream
func Start() {
go func() {
for {
select {
// listen for events
case ev := <-stream:
go func() {
// get registered queues for the event
queues, ok := registry[ev.Name]
if !ok {
return
}
// Get worker channel from queue and send the event
for _, queue := range queues {
worker := <-queue
worker <- ev
}
}()
}
}
}()
}
这是一个示例用法。
// Usage
Start()
type demoHandler struct {
db *sql.DB
}
type eventData struct {}
func (h *demoHandler) Work(ev *Event) {
// Do something
return
}
// Register handler
Register('some-event', &demoHandler{r})
Publish('some-event', &eventData{})
我将一个指向 demoHandler 的指针作为事件处理程序传递,因为它们需要访问底层的 sql 实例。每个worker queue使用同一个demoHandler是不是有问题?
我这辈子都想不通哪里出了问题!除了处理程序代码中的错误之外,我的代码中是否存在错误导致我所有的工作人员都宕机?
最佳答案
“在 go worker/event 系统中,worker 是否应该访问相同的结构(通过指针)来完成工作?” 不,这不是问题。如果您的处理程序中的代码访问 critical section,那将是一个问题,但我认为这不会导致您的程序阻塞。
您的服务器不会崩溃或阻塞,因为没有触发 panic ,并且您的程序正在单独的 goroutine 上监听和执行,这些 goroutine 是轻量级执行线程。
它可能必须与您用来发送和接收事件的 channel 有关。
发送和接收到 channel默认情况下是阻塞的。这意味着当您从 channel 发送或接收时,它将阻塞其 goroutine,直到另一端准备就绪。
在buffered channels的情况下,当缓冲区已满时发送 block ,当缓冲区为空时接收 block ,就像在您的流 channel 中一样:
var stream = make(chan *Event, 100)
您说:“在触发大约 100 个事件后,当事件发布时,监听器将停止被调用”。
因此,如果您调用 Publish 函数并执行 stream <- ev当“流” channel 缓冲区已满时,它将阻塞,直到 channel 有地方接收另一个元素。
我建议阅读一些关于 non-blocking channel operations 的内容.
也许阻塞发生在您实际使用代码的某些部分。
关于go - 在 go worker/event 系统中,worker 是否应该访问相同的结构(通过指针)来工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54517080/
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife
我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request
在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat
我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案