See also (Sorry, mainly in Japanese)
http://go-talks.appspot.com/github.com/lestrrat/go-slides/tree/master/2014-golangstudy-HDE
http://go-talks.appspot.com/github.com/lestrrat/go-slides/2014-yapcasia-go-for-perl-mongers/main.slide#1
22. “Go’s makes concurrency so easy, we
can just port our multi-process code in
an instant!”
Misconception
23.
24. ! PIDs to identify processes
! Processes can be signaled
! Processes can notify termination
Processes
25. ! No pid to identify goroutines
! No signals to communicate
! Goroutines don’t notify on exit
Goroutine
26. sub sub main {
my $pid = fork();
if (! defined $pid) { die “Failed to fork: $!” }
if (! $pid) { while(1) { do_stuff() } }
$SIG{CHLD} = sub {
my $pid = wait;
print “reaped $pidn”;
};
sleep 5;
kill TERM => $pid;
while (kill 0 => $pid) { sleep 1 }
}
Perl: Processes
27. func main() { // Won’t work
go func() {
for {
doStuff()
}
}
}
Go: A simple goroutine
28. func main() {
exitCh := make(chan struct{})
go func() {
defer func() { close(exitCh) }() // close upon termination
for {
doStuff()
}
}
<-exitCh // Wait for something to happen
}
Go: Detect termination
29. func main() {
exitCh := make(chan struct{})
incomingCh := make(chan struct{})
go func() {
defer func() { close(exitCh) }() // close upon termination
for {
select {
case <-incomingCh: // Got termination request
return
}
doStuff()
}
}
Go:Accept Termination Request
30. // Send request to terminate loop
time.AfterFunc(5 * time.Second, func() {
incomingCh <-struct{}{}
})
<-exitCh // Wait for something to happen
}
Go:Accept Termination Request
38. package Worker::Base;
# snip
sub foo {
# do stuff..
shift->something_overridable_in_child_class();
}
sub something_overridable_in_child_class { … }
Perl: Interaction Between Parent/Child
39. package Worker::Foo;
# snip
use parent qw(Worker::Base);
sub something_overridable_in_child_class { … }
sub work {
my $self = shift;
while (1) {
# do stuff…
$self->foo(); # Doesn’t translate very well into Go
}
}
Perl: Interaction Between Parent/Child
40.
41. ! No. Just No.
! Embedded structs + Automatic Delegation
Go: No Inheritance
42. type Name string
func (n Name) Greet() string {
return fmt.Sprintf(“Hello, my name is %s”, n)
}
Go: Name
43. n := Name(“Daisuke Maki”)
println(n.Greet()) // “Hello, my name is Daisuke Maki”
Go: Name
44. type Person struct {
Name // Embedded struct
Age uint // A regular field
}
Go: Person
45. p := &Person{
Name: Name(“Daisuke Maki”),
Age: 38
}
println(p.Greet()) // “Hello, my name is Daisuke Maki”
Go: Automatic Delegation
46. p.Greet() // → p.Name.Greet()
// The receiver is p.Name, not p.
Go: Automatic Delegation
48. type BaseWorker struct {}
func (w BaseWorker) Foo() {
// This only class BaseWorker.SomethingOverridableInChildClass()
w.SomethingOverridableInChildClass()
}
type FooWorker struct {
BaseWorker
}
func (w FooWorker) Work() {
for {
// Do interesting stuff…
w.Foo() // w.BaseWorker.Foo(), receiver is never FooWorker
}
}
Go: Another Failed Attempt
52. type Greeter interface {
Greet() string
}
func main() {
p := &Person{ Name: “Mary Jane”, Age: 30 }
n := Name(“John Doe”)
greeters := []Greeters{ p, n }
…
}
Go:Things that can Greet()
53. func sayHello(g Greeter) {
println(g.Greet())
}
for _, g := range greeters {
sayHello(g)
}
Go:Things that can Greet()
54. ! Think in terms of ability (methods)
! But note: no “base” method
implementations
Go: Interfaces
55. // WRONG! No methods for interfaces
func (g Greeter) SayHello() {
println(g.Greet())
}
Go: No “base” methods
56. // OK. Functions that take interfaces work
func sayHello(g Greeter) {
println(g.Greet())
}
// Each type would have to make this call
func (n Name) SayHello() {
sayHello(n) // Name is a Greeter
}
func (p Person) SayHello() {
sayHello(n) // And so is Person, through delegation to p.Name
}
Go: No “base” methods
57. ! Think of abilities, not Is-A, Has-A
! Compose from smaller components
Go: Designing Models