Created
February 24, 2014 22:38
-
-
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
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 ( | |
"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) | |
} | |
} |
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
$ 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