go.talks: inline the reader package in each main,
since playground doesn't currently handle packages
in other directories. Move the real implementation
to a separate realmain.go, so that the talk examples
don't depend on the external rss package. Update
the slides to reference fakemain.go.
R=adg
CC=golang-dev
https://golang.org/cl/9679044
diff --git a/2013/advconc.slide b/2013/advconc.slide
index 3f3869f..af61ce5 100644
--- a/2013/advconc.slide
+++ b/2013/advconc.slide
@@ -39,15 +39,15 @@
* Example: ping-pong
-.play advconc/pingpong1.go /STARTMAIN1/,/STOPMAIN1/
+.play advconc/pingpong/pingpong.go /STARTMAIN1/,/STOPMAIN1/
* Deadlock detection
-.play advconc/pingpongdeadlock.go /STARTMAIN1/,/STOPMAIN1/
+.play advconc/pingpongdeadlock/pingpongdeadlock.go /STARTMAIN1/,/STOPMAIN1/
* Panic dumps the stacks
-.play advconc/pingpongpanic.go /STARTMAIN1/,/STOPMAIN1/
+.play advconc/pingpongpanic/pingpongpanic.go /STARTMAIN1/,/STOPMAIN1/
* It's easy to go, but how to stop?
@@ -111,7 +111,7 @@
* Example
-.play advconc/fakemain.go /func main/,/^}/
+.play advconc/fakemain/fakemain.go /func main/,/^}/
* Subscribe
@@ -140,7 +140,7 @@
To implement the `Subscription` interface, define `Updates` and `Close`.
-.code advconc/reader/reader.go /func.* Updates/,/^}/
+.code advconc/fakemain/fakemain.go /func.* Updates/,/^}/
func (s *sub) Close() error {
// TODO: make loop exit
@@ -157,16 +157,16 @@
* Naive Implementation
# Not quite enough room for this; retry after format change:
-# .play advconc/naivemain.go /naiveSub\) loop/,/^}/
+# .play advconc/naivemain/naivemain.go /naiveSub\) loop/,/^}/
# also on subsequent slides.
-.play advconc/naivemain.go /STARTNAIVE/,/STOPNAIVE/
-.code advconc/naivemain.go /naiveSub\) Close/,/^}/
+.play advconc/naivemain/naivemain.go /STARTNAIVE /,/STOPNAIVE /
+.code advconc/naivemain/naivemain.go /naiveSub\) Close/,/^}/
* Bug 1: unsynchronized access to s.closed/s.err
-.code advconc/naivemain.go /STARTNAIVE/,/STOPNAIVE/ HLsync
-.code advconc/naivemain.go /naiveSub\) Close/,/^}/ HLsync
+.code advconc/naivemain/naivemain.go /STARTNAIVE /,/STOPNAIVE / HLsync
+.code advconc/naivemain/naivemain.go /naiveSub\) Close/,/^}/ HLsync
* Race Detector
@@ -174,19 +174,16 @@
# original is 400x1500
.image advconc/race.png 150 562
-.play advconc/naivemain.go /STARTNAIVE/,/s.err/ HLsync
-.code advconc/naivemain.go /naiveSub\) Close/,/^}/ HLsync
-
-#* Race demo
-#.play go1.1/race.go
+.play advconc/naivemain/naivemain.go /STARTNAIVE /,/s.err/ HLsync
+.code advconc/naivemain/naivemain.go /naiveSub\) Close/,/^}/ HLsync
* Bug 2: time.Sleep may keep loop running
-.code advconc/naivemain.go /STARTNAIVE/,/STOPNAIVE/ HLsleep
+.code advconc/naivemain/naivemain.go /STARTNAIVE/,/STOPNAIVE/ HLsleep
* Bug 3: loop may block forever on s.updates
-.code advconc/naivemain.go /STARTNAIVE/,/STOPNAIVE/ HLsend
+.code advconc/naivemain/naivemain.go /STARTNAIVE /,/STOPNAIVE / HLsend
* Solution
@@ -237,17 +234,17 @@
`Close` asks loop to exit and waits for a response.
-.code advconc/reader/reader.go /\*sub\) Close/,/^}/ HLchan
+.code advconc/fakemain/fakemain.go /\*sub\) Close/,/^}/ HLchan
`loop` handles `Close` by replying with the `Fetch` error and exiting.
-.code advconc/reader/reader.go /STARTCLOSEONLY /,/STOPCLOSEONLY / HLchan
+.code advconc/fakemain/fakemain.go /STARTCLOSEONLY /,/STOPCLOSEONLY / HLchan
* Case 2: Fetch
Schedule the next `Fetch` after some delay.
-.code advconc/reader/reader.go /STARTFETCHONLY /,/STOPFETCHONLY /
+.code advconc/fakemain/fakemain.go /STARTFETCHONLY /,/STOPFETCHONLY /
* Case 3: Send
@@ -271,19 +268,19 @@
Select never selects a blocking case.
-.play advconc/nilselect.go /func main/,/^}/
+.play advconc/nilselect/nilselect.go /func main/,/^}/
* Case 3: Send (fixed)
Enable send only when pending is non-empty.
-.code advconc/reader/reader.go /STARTSENDONLY /,/STOPSENDONLY / HLupdates
+.code advconc/fakemain/fakemain.go /STARTSENDONLY /,/STOPSENDONLY / HLupdates
* Select
Put the three cases together:
-.code advconc/reader/reader.go /STARTSELECT /,/STOPSELECT /
+.code advconc/fakemain/fakemain.go /STARTSELECT /,/STOPSELECT /
The cases interact via `err`, `next`, and `pending`.
@@ -295,35 +292,35 @@
- Bug 2: `time.Sleep` may keep loop running
- Bug 3: `loop` may block forever sending on `s.updates`
-.code advconc/reader/reader.go /STARTSELECT /,/STOPSELECT / HLcases
+.code advconc/fakemain/fakemain.go /STARTSELECT /,/STOPSELECT / HLcases
* We can improve loop further
* Issue: Fetch may return duplicates
-.code advconc/reader/reader.go /STARTFETCHVARS /,/STOPFETCHVARS / HLfetch
-.code advconc/reader/reader.go /STARTFETCHCASE /,/STOPFETCHCASE / HLfetch
+.code advconc/fakemain/fakemain.go /STARTFETCHVARS /,/STOPFETCHVARS / HLfetch
+.code advconc/fakemain/fakemain.go /STARTFETCHCASE /,/STOPFETCHCASE / HLfetch
* Fix: Filter items before adding to pending
-.code advconc/reader/reader.go /STARTSEEN /,/STOPSEEN / HLseen
-.code advconc/reader/reader.go /STARTDEDUPE /,/STOPDEDUPE / HLdupe
+.code advconc/fakemain/fakemain.go /STARTSEEN /,/STOPSEEN / HLseen
+.code advconc/fakemain/fakemain.go /STARTDEDUPE /,/STOPDEDUPE / HLdupe
* Issue: Pending queue grows without bound
-.code advconc/reader/reader.go /STARTDEDUPE /,/STOPDEDUPE / HLdupe
+.code advconc/fakemain/fakemain.go /STARTDEDUPE /,/STOPDEDUPE / HLdupe
* Fix: Disable fetch case when too much pending
const maxPending = 10
-.code advconc/reader/reader.go /STARTCAP /,/STOPCAP / HLcap
+.code advconc/fakemain/fakemain.go /STARTCAP /,/STOPCAP / HLcap
Could instead drop older items from the head of `pending`.
* Issue: Loop blocks on Fetch
-.code advconc/reader/reader.go /STARTDEDUPE /,/STOPDEDUPE / HLfetch
+.code advconc/fakemain/fakemain.go /STARTDEDUPE /,/STOPDEDUPE / HLfetch
* Fix: Run Fetch asynchronously
@@ -331,9 +328,9 @@
type fetchResult struct{ fetched []Item; next time.Time; err error }
-.code advconc/reader/reader.go /STARTFETCHDONE /,/STOPFETCHDONE / HLfetch
-.code advconc/reader/reader.go /STARTFETCHIF /,/STOPFETCHIF / HLfetch
-.code advconc/reader/reader.go /STARTFETCHASYNC /,/STOPFETCHASYNC / HLfetch
+.code advconc/fakemain/fakemain.go /STARTFETCHDONE /,/STOPFETCHDONE / HLfetch
+.code advconc/fakemain/fakemain.go /STARTFETCHIF /,/STOPFETCHIF / HLfetch
+.code advconc/fakemain/fakemain.go /STARTFETCHASYNC /,/STOPFETCHASYNC / HLfetch
* Implemented Subscribe
@@ -379,6 +376,3 @@
Go Tour (learn Go in your browser)
.link http://tour.golang.org
-
-*Go*Team*Fireside*Chat*
-5:20pm Room 2
diff --git a/2013/advconc/buffer.go b/2013/advconc/buffer/buffer.go
similarity index 100%
rename from 2013/advconc/buffer.go
rename to 2013/advconc/buffer/buffer.go
diff --git a/2013/advconc/dedupermain.go b/2013/advconc/dedupermain.go
deleted file mode 100644
index d613f93..0000000
--- a/2013/advconc/dedupermain.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package main
-
-import (
- "fmt"
- "math/rand"
- "time"
-
- . "code.google.com/p/go.talks/2013/advconc/reader"
-)
-
-func init() {
- rand.Seed(time.Now().UnixNano())
- FakeFetch = true
-}
-
-// STARTMAIN OMIT
-func main() {
- // STARTMERGECALL OMIT
- // Subscribe to some feeds, and create a merged update stream.
- merged := Dedupe(Merge(
- Subscribe(Fetch("blog.golang.org")),
- Subscribe(Fetch("blog.golang.org")),
- Subscribe(Fetch("blog.golang.org")),
- Subscribe(Fetch("googleblog.blogspot.com")),
- Subscribe(Fetch("googledevelopers.blogspot.com"))))
- // STOPMERGECALL OMIT
-
- // Close the subscriptions after some time.
- time.AfterFunc(3*time.Second, func() {
- fmt.Println("closed:", merged.Close())
- })
-
- // Print the stream.
- for it := range merged.Updates() {
- fmt.Println(it.Channel, it.Title)
- }
-
- panic("show me the stacks")
-}
-
-// STOPMAIN OMIT
diff --git a/2013/advconc/reader/reader.go b/2013/advconc/dedupermain/dedupermain.go
similarity index 87%
copy from 2013/advconc/reader/reader.go
copy to 2013/advconc/dedupermain/dedupermain.go
index 980f2bd..20867ac 100644
--- a/2013/advconc/reader/reader.go
+++ b/2013/advconc/dedupermain/dedupermain.go
@@ -1,11 +1,11 @@
-package reader
+// dedupermain runs the Subscribe example with several duplicate
+// subscriptions to demonstrate deduping.
+package main
import (
"fmt"
"math/rand"
"time"
-
- rss "github.com/jteeuwen/go-pkg-rss"
)
// STARTITEM OMIT
@@ -483,16 +483,9 @@
return d.updates
}
-// FakeFetch causes Fetch to use a fake fetcher instead of the real
-// one.
-var FakeFetch bool
-
// Fetch returns a Fetcher for Items from domain.
func Fetch(domain string) Fetcher {
- if FakeFetch {
- return fakeFetch(domain)
- }
- return realFetch(domain)
+ return fakeFetch(domain)
}
func fakeFetch(domain string) Fetcher {
@@ -524,49 +517,33 @@
return
}
-// realFetch returns a fetcher for the specified blogger domain.
-func realFetch(domain string) Fetcher {
- return NewFetcher(fmt.Sprintf("http://%s/feeds/posts/default?alt=rss", domain))
+func init() {
+ rand.Seed(time.Now().UnixNano())
}
-type fetcher struct {
- uri string
- feed *rss.Feed
- items []Item
-}
+// STARTMAIN OMIT
+func main() {
+ // STARTMERGECALL OMIT
+ // Subscribe to some feeds, and create a merged update stream.
+ merged := Dedupe(Merge(
+ Subscribe(Fetch("blog.golang.org")),
+ Subscribe(Fetch("blog.golang.org")),
+ Subscribe(Fetch("blog.golang.org")),
+ Subscribe(Fetch("googleblog.blogspot.com")),
+ Subscribe(Fetch("googledevelopers.blogspot.com"))))
+ // STOPMERGECALL OMIT
-// NewFetcher returns a Fetcher for uri.
-func NewFetcher(uri string) Fetcher {
- f := &fetcher{
- uri: uri,
+ // Close the subscriptions after some time.
+ time.AfterFunc(3*time.Second, func() {
+ fmt.Println("closed:", merged.Close())
+ })
+
+ // Print the stream.
+ for it := range merged.Updates() {
+ fmt.Println(it.Channel, it.Title)
}
- newChans := func(feed *rss.Feed, chans []*rss.Channel) {}
- newItems := func(feed *rss.Feed, ch *rss.Channel, items []*rss.Item) {
- for _, it := range items {
- f.items = append(f.items, Item{
- Channel: ch.Title,
- GUID: it.Guid,
- Title: it.Title,
- })
- }
- }
- f.feed = rss.New(1 /*minimum interval in minutes*/, true /*respect limit*/, newChans, newItems)
- return f
+
+ panic("show me the stacks")
}
-func (f *fetcher) Fetch() (items []Item, next time.Time, err error) {
- fmt.Println("fetching", f.uri)
- if err = f.feed.Fetch(f.uri, nil); err != nil {
- return
- }
- items = f.items
- f.items = nil
- next = time.Now().Add(time.Duration(f.feed.SecondsTillUpdate()) * time.Second)
- return
-}
-
-// TODO: in a longer talk: move the Subscribe function onto a Reader type, to
-// support dynamically adding and removing Subscriptions. Reader should dedupe.
-
-// TODO: in a longer talk: make successive Subscribe calls for the same uri
-// share the same underlying Subscription, but provide duplicate streams.
+// STOPMAIN OMIT
diff --git a/2013/advconc/fakemain.go b/2013/advconc/fakemain.go
deleted file mode 100644
index 5c2d08c..0000000
--- a/2013/advconc/fakemain.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package main
-
-import (
- "fmt"
- "math/rand"
- "time"
-
- . "code.google.com/p/go.talks/2013/advconc/reader"
-)
-
-func init() {
- rand.Seed(time.Now().UnixNano())
- FakeFetch = true
-}
-
-// STARTMAIN OMIT
-func main() {
- // STARTMERGECALL OMIT
- // Subscribe to some feeds, and create a merged update stream.
- merged := Merge(
- Subscribe(Fetch("blog.golang.org")),
- Subscribe(Fetch("googleblog.blogspot.com")),
- Subscribe(Fetch("googledevelopers.blogspot.com")))
- // STOPMERGECALL OMIT
-
- // Close the subscriptions after some time.
- time.AfterFunc(3*time.Second, func() {
- fmt.Println("closed:", merged.Close())
- })
-
- // Print the stream.
- for it := range merged.Updates() {
- fmt.Println(it.Channel, it.Title)
- }
-
- panic("show me the stacks")
-}
-
-// STOPMAIN OMIT
diff --git a/2013/advconc/reader/reader.go b/2013/advconc/fakemain/fakemain.go
similarity index 87%
copy from 2013/advconc/reader/reader.go
copy to 2013/advconc/fakemain/fakemain.go
index 980f2bd..52e0091 100644
--- a/2013/advconc/reader/reader.go
+++ b/2013/advconc/fakemain/fakemain.go
@@ -1,11 +1,10 @@
-package reader
+// fakemain runs the Subscribe example with a fake RSS fetcher.
+package main
import (
"fmt"
"math/rand"
"time"
-
- rss "github.com/jteeuwen/go-pkg-rss"
)
// STARTITEM OMIT
@@ -483,16 +482,9 @@
return d.updates
}
-// FakeFetch causes Fetch to use a fake fetcher instead of the real
-// one.
-var FakeFetch bool
-
// Fetch returns a Fetcher for Items from domain.
func Fetch(domain string) Fetcher {
- if FakeFetch {
- return fakeFetch(domain)
- }
- return realFetch(domain)
+ return fakeFetch(domain)
}
func fakeFetch(domain string) Fetcher {
@@ -524,49 +516,31 @@
return
}
-// realFetch returns a fetcher for the specified blogger domain.
-func realFetch(domain string) Fetcher {
- return NewFetcher(fmt.Sprintf("http://%s/feeds/posts/default?alt=rss", domain))
+func init() {
+ rand.Seed(time.Now().UnixNano())
}
-type fetcher struct {
- uri string
- feed *rss.Feed
- items []Item
-}
+// STARTMAIN OMIT
+func main() {
+ // STARTMERGECALL OMIT
+ // Subscribe to some feeds, and create a merged update stream.
+ merged := Merge(
+ Subscribe(Fetch("blog.golang.org")),
+ Subscribe(Fetch("googleblog.blogspot.com")),
+ Subscribe(Fetch("googledevelopers.blogspot.com")))
+ // STOPMERGECALL OMIT
-// NewFetcher returns a Fetcher for uri.
-func NewFetcher(uri string) Fetcher {
- f := &fetcher{
- uri: uri,
+ // Close the subscriptions after some time.
+ time.AfterFunc(3*time.Second, func() {
+ fmt.Println("closed:", merged.Close())
+ })
+
+ // Print the stream.
+ for it := range merged.Updates() {
+ fmt.Println(it.Channel, it.Title)
}
- newChans := func(feed *rss.Feed, chans []*rss.Channel) {}
- newItems := func(feed *rss.Feed, ch *rss.Channel, items []*rss.Item) {
- for _, it := range items {
- f.items = append(f.items, Item{
- Channel: ch.Title,
- GUID: it.Guid,
- Title: it.Title,
- })
- }
- }
- f.feed = rss.New(1 /*minimum interval in minutes*/, true /*respect limit*/, newChans, newItems)
- return f
+
+ panic("show me the stacks")
}
-func (f *fetcher) Fetch() (items []Item, next time.Time, err error) {
- fmt.Println("fetching", f.uri)
- if err = f.feed.Fetch(f.uri, nil); err != nil {
- return
- }
- items = f.items
- f.items = nil
- next = time.Now().Add(time.Duration(f.feed.SecondsTillUpdate()) * time.Second)
- return
-}
-
-// TODO: in a longer talk: move the Subscribe function onto a Reader type, to
-// support dynamically adding and removing Subscriptions. Reader should dedupe.
-
-// TODO: in a longer talk: make successive Subscribe calls for the same uri
-// share the same underlying Subscription, but provide duplicate streams.
+// STOPMAIN OMIT
diff --git a/2013/advconc/fakemainnomerge.go b/2013/advconc/fakemainnomerge.go
deleted file mode 100644
index 8ab960d..0000000
--- a/2013/advconc/fakemainnomerge.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package main
-
-import (
- "fmt"
- "math/rand"
- "time"
-
- . "code.google.com/p/go.talks/2013/advconc/reader"
-)
-
-func init() {
- rand.Seed(time.Now().UnixNano())
- FakeFetch = true
-}
-
-// STARTMAIN OMIT
-func main() {
- sub := Subscribe(Fetch("blog.golang.org"))
-
- // Close the subscription after some time.
- time.AfterFunc(3*time.Second, func() {
- fmt.Println("closed:", sub.Close())
- })
-
- // Print the stream.
- for it := range sub.Updates() {
- fmt.Println(it.Channel, it.Title)
- }
-
- panic("show me the stacks")
-}
-
-// STOPMAIN OMIT
diff --git a/2013/advconc/naivemain.go b/2013/advconc/naivemain.go
deleted file mode 100644
index a5a5155..0000000
--- a/2013/advconc/naivemain.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package main
-
-import (
- "fmt"
- "math/rand"
- "time"
-
- . "code.google.com/p/go.talks/2013/advconc/reader"
-)
-
-func NaiveSubscribe(fetcher Fetcher) Subscription {
- s := &naiveSub{
- fetcher: fetcher,
- updates: make(chan Item),
- }
- go s.loop()
- return s
-}
-
-type naiveSub struct {
- fetcher Fetcher
- updates chan Item
- closed bool
- err error
-}
-
-func (s *naiveSub) Updates() <-chan Item {
- return s.updates
-}
-
-func (s *naiveSub) loop() {
- // STARTNAIVE OMIT
- for {
- if s.closed { // HLsync
- close(s.updates)
- return
- }
- items, next, err := s.fetcher.Fetch()
- if err != nil {
- s.err = err // HLsync
- time.Sleep(10 * time.Second) // HLsleep
- continue
- }
- for _, item := range items {
- s.updates <- item // HLsend
- }
- if now := time.Now(); next.After(now) {
- time.Sleep(next.Sub(now)) // HLsleep
- }
- }
- // STOPNAIVE OMIT
-}
-
-func (s *naiveSub) Close() error {
- s.closed = true // HLsync
- return s.err // HLsync
-}
-
-func init() {
- rand.Seed(time.Now().UnixNano())
- FakeFetch = true
-}
-
-func main() {
- // Subscribe to some feeds, and create a merged update stream.
- merged := Merge(
- NaiveSubscribe(Fetch("blog.golang.org")),
- NaiveSubscribe(Fetch("googleblog.blogspot.com")),
- NaiveSubscribe(Fetch("googledevelopers.blogspot.com")))
-
- // Close the subscriptions after some time.
- time.AfterFunc(3*time.Second, func() {
- fmt.Println("closed:", merged.Close())
- })
-
- // Print the stream.
- for it := range merged.Updates() {
- fmt.Println(it.Channel, it.Title)
- }
-
- // The loops are still running. Let the race detector notice.
- time.Sleep(1 * time.Second)
-
- panic("show me the stacks")
-}
diff --git a/2013/advconc/reader/reader.go b/2013/advconc/naivemain/naivemain.go
similarity index 87%
copy from 2013/advconc/reader/reader.go
copy to 2013/advconc/naivemain/naivemain.go
index 980f2bd..de4c11b 100644
--- a/2013/advconc/reader/reader.go
+++ b/2013/advconc/naivemain/naivemain.go
@@ -1,11 +1,11 @@
-package reader
+// naivemain runs the Subscribe example with the naive Subscribe
+// implementation and a fake RSS fetcher.
+package main
import (
"fmt"
"math/rand"
"time"
-
- rss "github.com/jteeuwen/go-pkg-rss"
)
// STARTITEM OMIT
@@ -483,16 +483,9 @@
return d.updates
}
-// FakeFetch causes Fetch to use a fake fetcher instead of the real
-// one.
-var FakeFetch bool
-
// Fetch returns a Fetcher for Items from domain.
func Fetch(domain string) Fetcher {
- if FakeFetch {
- return fakeFetch(domain)
- }
- return realFetch(domain)
+ return fakeFetch(domain)
}
func fakeFetch(domain string) Fetcher {
@@ -524,49 +517,77 @@
return
}
-// realFetch returns a fetcher for the specified blogger domain.
-func realFetch(domain string) Fetcher {
- return NewFetcher(fmt.Sprintf("http://%s/feeds/posts/default?alt=rss", domain))
-}
-
-type fetcher struct {
- uri string
- feed *rss.Feed
- items []Item
-}
-
-// NewFetcher returns a Fetcher for uri.
-func NewFetcher(uri string) Fetcher {
- f := &fetcher{
- uri: uri,
+func NaiveSubscribe(fetcher Fetcher) Subscription {
+ s := &naiveSub{
+ fetcher: fetcher,
+ updates: make(chan Item),
}
- newChans := func(feed *rss.Feed, chans []*rss.Channel) {}
- newItems := func(feed *rss.Feed, ch *rss.Channel, items []*rss.Item) {
- for _, it := range items {
- f.items = append(f.items, Item{
- Channel: ch.Title,
- GUID: it.Guid,
- Title: it.Title,
- })
+ go s.loop()
+ return s
+}
+
+type naiveSub struct {
+ fetcher Fetcher
+ updates chan Item
+ closed bool
+ err error
+}
+
+func (s *naiveSub) Updates() <-chan Item {
+ return s.updates
+}
+
+func (s *naiveSub) loop() {
+ // STARTNAIVE OMIT
+ for {
+ if s.closed { // HLsync
+ close(s.updates)
+ return
+ }
+ items, next, err := s.fetcher.Fetch()
+ if err != nil {
+ s.err = err // HLsync
+ time.Sleep(10 * time.Second) // HLsleep
+ continue
+ }
+ for _, item := range items {
+ s.updates <- item // HLsend
+ }
+ if now := time.Now(); next.After(now) {
+ time.Sleep(next.Sub(now)) // HLsleep
}
}
- f.feed = rss.New(1 /*minimum interval in minutes*/, true /*respect limit*/, newChans, newItems)
- return f
+ // STOPNAIVE OMIT
}
-func (f *fetcher) Fetch() (items []Item, next time.Time, err error) {
- fmt.Println("fetching", f.uri)
- if err = f.feed.Fetch(f.uri, nil); err != nil {
- return
+func (s *naiveSub) Close() error {
+ s.closed = true // HLsync
+ return s.err // HLsync
+}
+
+func init() {
+ rand.Seed(time.Now().UnixNano())
+}
+
+func main() {
+ // Subscribe to some feeds, and create a merged update stream.
+ merged := Merge(
+ NaiveSubscribe(Fetch("blog.golang.org")),
+ NaiveSubscribe(Fetch("googleblog.blogspot.com")),
+ NaiveSubscribe(Fetch("googledevelopers.blogspot.com")))
+
+ // Close the subscriptions after some time.
+ time.AfterFunc(3*time.Second, func() {
+ fmt.Println("closed:", merged.Close())
+ })
+
+ // Print the stream.
+ for it := range merged.Updates() {
+ fmt.Println(it.Channel, it.Title)
}
- items = f.items
- f.items = nil
- next = time.Now().Add(time.Duration(f.feed.SecondsTillUpdate()) * time.Second)
- return
+
+ // The loops are still running. Let the race detector notice.
+ time.Sleep(1 * time.Second)
+
+ panic("show me the stacks")
}
-
-// TODO: in a longer talk: move the Subscribe function onto a Reader type, to
-// support dynamically adding and removing Subscriptions. Reader should dedupe.
-
-// TODO: in a longer talk: make successive Subscribe calls for the same uri
-// share the same underlying Subscription, but provide duplicate streams.
diff --git a/2013/advconc/naivemainnomerge.go b/2013/advconc/naivemainnomerge.go
deleted file mode 100644
index f4a94ad..0000000
--- a/2013/advconc/naivemainnomerge.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package main
-
-import (
- "fmt"
- "math/rand"
- "time"
-
- . "code.google.com/p/go.talks/2013/advconc/reader"
-)
-
-func init() {
- rand.Seed(time.Now().UnixNano())
- FakeFetch = true
-}
-
-func main() {
- sub := NaiveSubscribe(Fetch("blog.golang.org"))
-
- // Close the subscription after some time.
- time.AfterFunc(3*time.Second, func() {
- fmt.Println("closed:", sub.Close())
- })
-
- // Print the stream.
- for it := range sub.Updates() {
- fmt.Println(it.Channel, it.Title)
- }
-
- panic("show me the stacks")
-}
diff --git a/2013/advconc/nilselect.go b/2013/advconc/nilselect/nilselect.go
similarity index 100%
rename from 2013/advconc/nilselect.go
rename to 2013/advconc/nilselect/nilselect.go
diff --git a/2013/advconc/pingpong/pingpong.go b/2013/advconc/pingpong/pingpong.go
new file mode 100644
index 0000000..80acfff
--- /dev/null
+++ b/2013/advconc/pingpong/pingpong.go
@@ -0,0 +1,31 @@
+package main
+
+import (
+ "fmt"
+ "time"
+)
+
+// STARTMAIN1 OMIT
+type Ball struct{ hits int }
+
+func main() {
+ table := make(chan *Ball)
+ go player("ping", table)
+ go player("pong", table)
+
+ table <- new(Ball) // game on; toss the ball
+ time.Sleep(1 * time.Second)
+ <-table // game over; grab the ball
+}
+
+func player(name string, table chan *Ball) {
+ for {
+ ball := <-table
+ ball.hits++
+ fmt.Println(name, ball.hits)
+ time.Sleep(100 * time.Millisecond)
+ table <- ball
+ }
+}
+
+// STOPMAIN1 OMIT
diff --git a/2013/advconc/pingpong2.go b/2013/advconc/pingpong2.go
deleted file mode 100644
index 0aca88f..0000000
--- a/2013/advconc/pingpong2.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package main
-
-import (
- "fmt"
- "time"
-)
-
-// STARTMAIN1 OMIT
-type Ball struct{}
-
-func main() {
- table := make(chan Ball)
- stop1, stop2 := make(chan int), make(chan int)
- go player("ping", table, stop1)
- go player("pong", table, stop2)
-
- table <- Ball{}
- time.Sleep(1 * time.Second)
- stop1 <- 1
- stop2 <- 1
- <-stop1
- <-stop2
-}
-
-// STOPMAIN1 OMIT
-
-// STARTPLAYER1 OMIT
-func player(name string, table chan Ball, stop chan int) {
- for {
- select {
- case ball := <-table:
- fmt.Println(name)
- time.Sleep(100 * time.Millisecond)
- table <- ball
- case <-stop:
- fmt.Println(name, "done")
- stop <- 1
- }
- }
-}
-
-// STOPPLAYER1 OMIT
diff --git a/2013/advconc/pingpongdeadlock.go b/2013/advconc/pingpongdeadlock/pingpongdeadlock.go
similarity index 100%
rename from 2013/advconc/pingpongdeadlock.go
rename to 2013/advconc/pingpongdeadlock/pingpongdeadlock.go
diff --git a/2013/advconc/pingpongpanic.go b/2013/advconc/pingpongpanic/pingpongpanic.go
similarity index 100%
rename from 2013/advconc/pingpongpanic.go
rename to 2013/advconc/pingpongpanic/pingpongpanic.go
diff --git a/2013/advconc/reader/reader.go b/2013/advconc/realmain/realmain.go
similarity index 92%
rename from 2013/advconc/reader/reader.go
rename to 2013/advconc/realmain/realmain.go
index 980f2bd..6c340e7 100644
--- a/2013/advconc/reader/reader.go
+++ b/2013/advconc/realmain/realmain.go
@@ -1,4 +1,5 @@
-package reader
+// realmain runs the Subscribe example with a real RSS fetcher.
+package main
import (
"fmt"
@@ -570,3 +571,38 @@
// TODO: in a longer talk: make successive Subscribe calls for the same uri
// share the same underlying Subscription, but provide duplicate streams.
+
+func init() {
+ rand.Seed(time.Now().UnixNano())
+}
+
+// STARTMAIN OMIT
+func main() {
+ // STARTMERGECALL OMIT
+ // Subscribe to some feeds, and create a merged update stream.
+ merged := Merge(
+ Subscribe(Fetch("blog.golang.org")),
+ Subscribe(Fetch("googleblog.blogspot.com")),
+ Subscribe(Fetch("googledevelopers.blogspot.com")))
+ // STOPMERGECALL OMIT
+
+ // Close the subscriptions after some time.
+ time.AfterFunc(3*time.Second, func() {
+ fmt.Println("closed:", merged.Close())
+ })
+
+ // Print the stream.
+ for it := range merged.Updates() {
+ fmt.Println(it.Channel, it.Title)
+ }
+
+ // Uncomment the panic below to dump the stack traces. This
+ // will show several stacks for persistent HTTP connections
+ // created by the real RSS client. To clean these up, we'll
+ // need to extend Fetcher with a Close method and plumb this
+ // through the RSS client implementation.
+ //
+ // panic("show me the stacks")
+}
+
+// STOPMAIN OMIT