Created
May 28, 2016 22:42
-
-
Save tomnomnom/0ef06cd9221161499bae9ffd28383f7f to your computer and use it in GitHub Desktop.
Using Go's channels to spread work across a bunch of worker goroutines
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"net" | |
"sync" | |
"time" | |
) | |
const ( | |
// numWorkers is the number of worker goroutines to use | |
numWorkers = 10 | |
// connectTimeout is the time to wait before considering a port closed | |
connectTimeout = time.Millisecond * 500 | |
) | |
// A job contains the host:port to connect to and the result | |
// of that connection attempt | |
type job struct { | |
host string | |
res bool | |
} | |
// worker waits for jobs on an input channel, tries to connect to | |
// the job host:port, adds the result to the job and sends it on | |
// the provided output channel | |
func worker(in chan job, out chan job) { | |
for { | |
j, ok := <-in | |
if !ok { | |
return | |
} | |
conn, err := net.DialTimeout("tcp", j.host, connectTimeout) | |
if err == nil { | |
j.res = true | |
_ = conn.Close() | |
} | |
out <- j | |
} | |
} | |
func main() { | |
// Use a WaitGroup to make sure we get the result from | |
// every job in the queue | |
var wg sync.WaitGroup | |
// Prep a job queue | |
var jobs []job | |
for i := 1; i <= 65535; i++ { | |
wg.Add(1) | |
jobs = append(jobs, job{fmt.Sprintf("192.168.1.23:%d", i), false}) | |
} | |
// Spin up some workers | |
in := make(chan job) | |
out := make(chan job) | |
for i := 0; i < numWorkers; i++ { | |
go worker(in, out) | |
} | |
// We need to start handling job results before we add | |
// any to the queue otherwise it will deadlock | |
go func() { | |
for { | |
r, ok := <-out | |
if !ok { | |
return | |
} | |
if r.res { | |
fmt.Printf("%s is open\n", r.host) | |
} | |
wg.Done() | |
} | |
}() | |
// Feed the jobs into the queue | |
for _, j := range jobs { | |
in <- j | |
} | |
// Wait for everything to finish and then close the | |
// input and output channels | |
wg.Wait() | |
close(in) | |
close(out) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment