Skip to content

Instantly share code, notes, and snippets.

@mstine
Created February 24, 2014 22:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mstine/9198783 to your computer and use it in GitHub Desktop.
Save mstine/9198783 to your computer and use it in GitHub Desktop.
Go port of NAV calculation from Ch. 2 of Programming Concurrency on the JVM
package main
import (
"bufio"
"errors"
"fmt"
"net/http"
"os"
"strconv"
"strings"
"time"
)
func getPrice(ticker string) (float64, error) {
url := "http://ichart.finance.yahoo.com/table.csv?s=" + ticker
resp, err := http.Get(url)
if err != nil {
return 0, errors.New("Couldn't load stock data from Yahoo")
}
if resp.StatusCode == 404 {
return 0, fmt.Errorf("Couldn't find stock: %v", ticker)
}
scanner := bufio.NewScanner(resp.Body)
// Discard the header
scanner.Scan()
// Obtain the latest price
scanner.Scan()
data := scanner.Text()
dataItems := strings.Split(data, ",")
// Price is the last value
return strconv.ParseFloat(dataItems[len(dataItems)-1], 64)
}
func readTickers() (map[string]int, error) {
file, err := os.Open("stocks.txt")
defer file.Close()
if err != nil {
return nil, err
}
tickers := make(map[string]int)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
stockInfo := scanner.Text()
stockInfoData := strings.Split(stockInfo, ",")
stockTicker := stockInfoData[0]
quantity := stockInfoData[1]
tickers[stockTicker], _ = strconv.Atoi(quantity)
}
return tickers, nil
}
func timeAndCompute(strategy func(map[string]int) (float64, error)) error {
t0 := time.Now()
stocks, err := readTickers()
if err != nil {
return err
}
nav, err := strategy(stocks)
if err != nil {
return err
}
t1 := time.Now()
fmt.Printf("Your net asset value is $%f\n", nav)
fmt.Printf("Time (seconds) taken %v\n", t1.Sub(t0))
return nil
}
func sequentialNav(stocks map[string]int) (float64, error) {
netAssetValue := 0.0
for k, v := range stocks {
price, err := getPrice(k)
if err != nil {
return 0.0, err
}
netAssetValue += float64(v) * price
}
return netAssetValue, nil
}
type Pair struct {
Price float64
Shares int
Error error
}
func concurrentNav(stocks map[string]int) (float64, error) {
pairs := make(chan Pair)
for k, v := range stocks {
go func(symbol string, shares int) {
price, err := getPrice(symbol)
if err != nil {
pairs <- Pair{0.0, 0, err}
}
pairs <- Pair{price, shares, nil}
}(k, v)
}
netAssetValue := 0.0
for i := 0; i < len(stocks); i++ {
pair := <-pairs
if pair.Error == nil {
netAssetValue += float64(pair.Shares) * pair.Price
}
}
return netAssetValue, nil
}
func main() {
fmt.Println("Sequential:")
err := timeAndCompute(sequentialNav)
if err != nil {
fmt.Println(err)
}
fmt.Println("Concurrent:")
err = timeAndCompute(concurrentNav)
if err != nil {
fmt.Println(err)
}
}
$ go run conc.go
Sequential:
Your net asset value is $23037608.480000
Time (seconds) taken 17.35814598s
Concurrent:
Your net asset value is $23037608.480000
Time (seconds) taken 974.335331ms
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment