golang で JS 的な addEventListener/dispatchEvent 的なことをしたいときどうするか?

emission

JS にあるようなのと全く同じ様に「イベント名」でイベントの種類を識別して任意の「イベントオブジェクト」をやりとりする。

On/Off/Once とか jQuery にあるような便利メソッドがついてる。

リフレクションで型変換は隠蔽されているが、もしリスナーとエミッターとで型が食い違っていると、実行時エラーになる。

package main

import (
	"github.com/chuckpreslar/emission"
	"log"
)

type ClickEvent struct {
	button string
}

type KeyEvent struct {
	key string
}

func main() {
	emitter := emission.NewEmitter()
	emitter.On("click", func (ev *ClickEvent) {
		log.Printf("onclick %v", ev)
	})
	emitter.On("key", func (ev *KeyEvent) {
		log.Printf("onkey %v", ev)
	})

	emitter.Emit("click", &ClickEvent{ button : "left" })
	emitter.Emit("click", &ClickEvent{ button : "right" })
	emitter.Emit("key", &KeyEvent{ key : "A" })

	// panic
	emitter.Emit("key", &ClickEvent{ button : "right" })

	// or also panic
	emitter.On("key", func (ev *ClickEvent) {
		log.Printf("onkey2 %v", ev)
	})
	emitter.Emit("key", &KeyEvent{ button : "right" })
}

go-pubsub

Pub/Sub/Leave というメソッドが生えている。Pub は Emit/Dispatch, Sub は addListener/On, Leave は removeListener/Off に対応する。

「イベント名」というパラメータが存在せず、型の選択によって自動的にディスパッチされる。よって型がマッチしなければリスナーは実行されないので、原理的に型変換の実行時エラーは発生しない (もし間違えた場合単に実行時になって「呼ばれない」ことに気付く)

package main

import (
	"github.com/mattn/go-pubsub"
	"log"
	"time"
)

type ClickEvent struct {
	button string
}

type KeyEvent struct {
	key string
}

func main() {
	ps := pubsub.New()

	ps.Sub(func(ev *ClickEvent) {
		log.Printf("onclick %v", ev)
	})
	ps.Sub(func(ev *KeyEvent) {
		log.Printf("onkey %v", ev)
	})

	ps.Pub(&ClickEvent{button: "left"})
	ps.Pub(&ClickEvent{button: "right"})
	ps.Pub(&KeyEvent{key: "A"})

	time.Sleep(100 * time.Millisecond)
}

サンプルコード書いてて気付いたが、Sub に登録した関数は Sub を呼んだ順あるいは Pub を呼んだ順に関係なく実行されうる? (ref. 登録された関数を go で呼んでる)

下記コードのように time.Sleep の代わりに Pub/Sub によって終了を待とうとするとたまに失敗する。(完全に終了を待つ方法がわからなかった)

package main

import (
	"github.com/mattn/go-pubsub"
	"log"
)

type ClickEvent struct {
	button string
}

type KeyEvent struct {
	key string
}

func main() {
	ps := pubsub.New()

	ps.Sub(func(ev *ClickEvent) {
		log.Printf("onclick %v", ev)
	})
	ps.Sub(func(ev *KeyEvent) {
		log.Printf("onkey %v", ev)
	})

	ps.Pub(&ClickEvent{button: "left"})
	ps.Pub(&ClickEvent{button: "right"})
	ps.Pub(&KeyEvent{key: "A"})

	// waiting for processing all messages
	// -> FAIL
	done := make(chan bool)
	ps.Sub(func(b bool) {
		ps.Close()
		done <- true
	})
	ps.Pub(true)
	<-done
}
  1. トップ
  2. tech
  3. golang で event emitter/dispatcher 的なもの

アース製薬 アースノーマット 蚊取り黒ブタ 60日セット (器具+45mL) -

5.0 / 5.0

これを寝室とリビングの1つずつ買った。黒いブタバージョンで可愛い。電源ケーブルが「しっぽ」になっているのも地味にいいデザインだなあと思う。昔ながらの陶器のブタの蚊取り線香って僕は現実で見たことがないけど、それでもブタの形が「蚊取り線香」をイメージさせるというのは、なんかおもしろい。

アースノーマットって、動いている気配が一切ないのでちょっと不安だけど一応効いてるみたい。

なんかいまいちよくわからない (以下はgolangでのコードだけど、特にgolangに限らないはなし)

// PBO 作成
buffer := gl.GenBuffer()
buffer.Bind(gl.PIXEL_UNPACK_BUFFER)
gl.BufferData(gl.PIXEL_UNPACK_BUFFER, width*height*4, nil, gl.STREAM_DRAW)
buffer.Unbind(gl.PIXEL_UNPACK_BUFFER)

// テクスチャ作成
texture := gl.GenTexture()
texture.Bind(gl.TEXTURE_2D)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_INT_8_8_8_8_REV, nil)
texture.Unbind(gl.TEXTURE_2D)

以上のように初期化して、

texture.Bind(gl.TEXTURE_2D)
buffer.Bind(gl.PIXEL_UNPACK_BUFFER)
bitmap := *(*[]uint32)(gl.MapBufferSlice(gl.PIXEL_UNPACK_BUFFER, gl.READ_WRITE, 4))
// ... do something
gl.UnmapBuffer(gl.PIXEL_UNPACK_BUFFER)
drawBuffer.Unbind(gl.PIXEL_UNPACK_BUFFER)


buffer.Bind(gl.PIXEL_UNPACK_BUFFER)
gl.TexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, fftBinSize, historySize, gl.RGBA, gl.UNSIGNED_INT_8_8_8_8_REV, nil)
buffer.Unbind(gl.PIXEL_UNPACK_BUFFER)

以上のように更新をしてる。

このとき、TexSubImage2D の引数にある gl.RGBA 及び gl.UNSIGNED_INT_8_8_8_8_REV を正しく(?)指定しないと余計に CPU 負荷がかかる。つまりGPUがネイティブに取り扱えるかどうかで決まると思うんだけど、何が GPU ネイティブなのかがよくわからない…

多少試した感じだと

  • gl.RGBA/gl.UNSIGNED_INT_8_8_8_8_REV
  • gl.BGRA/gl.UNSIGNED_INT_8_8_8_8_REV

の場合だけ高速に動作する。gl.RGBA/gl.UNSIGNED_INT_8_8_8_8 とかだとダメ。gl.RGBA は OpenGL ネイティブがこの型式だかららしいけど、gl.BGRA でもいけるのがよくわからない……

  1. トップ
  2. tech
  3. OpenGL で PBO 使ってテクスチャ更新するときの型式