Skip to content

Instantly share code, notes, and snippets.

@chakrit
Last active December 23, 2015 11:00
Show Gist options
  • Save chakrit/2e40dd624d940a8de722 to your computer and use it in GitHub Desktop.
Save chakrit/2e40dd624d940a8de722 to your computer and use it in GitHub Desktop.
*.so
*.h
main
require 'ffi'
module GoMachine
extend FFI::Library
ffi_lib './gomachine.so'
attach_function :Start, [], :void
attach_function :Request, [:string], :uint64
attach_function :Result, [:uint64], :string
end
MAGNITUDE = 50
GoMachine.Start
(1..MAGNITUDE).
map { |n| GoMachine.Request("https://api.omise.co/ping") }.
map { |id| GoMachine.Result(id) }.
each do |result|
puts result
end
package main
import "C"
import "fmt"
import "net/http"
import "sync/atomic"
import "io/ioutil"
var counter int32
const (
PortGet = iota * 1000
PortSet
)
type Port chan string
type PortCommand struct {
Cmd int
ID int32
Port Port
Result chan Port
}
type PortActor struct {
registry map[int32]Port
commands chan *PortCommand
}
func NewPortActor() *PortActor {
return &PortActor{
map[int32]Port{},
make(chan *PortCommand, 10),
}
}
func (a *PortActor) Start() {
go func() {
for cmd := range a.commands {
switch cmd.Cmd {
case PortGet:
cmd.Result <- a.registry[cmd.ID]
case PortSet:
a.registry[cmd.ID] = cmd.Port
default:
panic("actor received invalid command.")
}
}
}()
}
func (a *PortActor) Set(id int32, port Port) {
a.commands <- &PortCommand{PortSet, id, port, nil}
}
func (a *PortActor) Delete(id int32) Port {
result := make(chan Port)
a.commands <- &PortCommand{PortGet, id, nil, result}
return <-result
}
var actor *PortActor
//export Start
func Start() {
actor = NewPortActor()
actor.Start()
}
//export Request
func Request(rawurl *C.char) int32 {
url := C.GoString(rawurl)
// fmt.Println(url)
// return 0
port := make(Port)
go func() {
// TODO: Don't ignore error
defer close(port)
response, err := http.Get(url)
if err != nil {
fmt.Println(err)
port <- err.Error()
return
}
if response.Body != nil {
defer response.Body.Close()
}
bytes, err := ioutil.ReadAll(response.Body)
port <- string(bytes)
_ = err
}()
id := atomic.AddInt32(&counter, 1)
actor.Set(id, port)
return id
}
//export Result
func Result(id int32) string {
return <-actor.Delete(id)
}
func main() {} // required, but ignored
// Test:
//
// func main() {
// resp, e := http.Get("https://api.omise.co/ping")
// if e != nil {
// panic(e)
// }
// bytes, e := ioutil.ReadAll(resp.Body)
// if e != nil {
// panic(e)
// }
// fmt.Println(string(bytes))
// }
rm gomachine.so
go build -buildmode=c-shared -o gomachine.so main.go
ruby bridge.rb
@chakrit
Copy link
Author

chakrit commented Dec 23, 2015

./test.sh 1.71s user 0.41s system 48% cpu 4.423 total

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment