Situation:
I've a slice of values and need to pick up a randomly chosen value from it. Then I want to concatenate it with a fixed string. This is my code so far:
func main() {
//create the reasons slice and append reasons to it
reasons := make([]string, 0)
reasons = append(reasons,
"Locked out",
"Pipes broke",
"Food poisoning",
"Not feeling well")
message := fmt.Sprint("Gonna work from home...", pick a random reason )
}
Question:
Is there a built-in function, which can help me by doing the "pick a random reason" part?
Use function Intn from rand package to select a random index.
import (
"math/rand"
"time"
)
// ...
rand.Seed(time.Now().Unix()) // initialize global pseudo random generator
message := fmt.Sprint("Gonna work from home...", reasons[rand.Intn(len(reasons))])
Other solution is to use Rand object.
s := rand.NewSource(time.Now().Unix())
r := rand.New(s) // initialize local pseudorandom generator
r.Intn(len(reasons))
Just pick a random integer mod slice length:
rand.Seed(time.Now().Unix())
reasons := []string{
"Locked out",
"Pipes broke",
"Food poisoning",
"Not feeling well",
}
n := rand.Int() % len(reasons)
fmt.Print("Gonna work from home...", reasons[n])
Playground: http://play.golang.org/p/fEHElLJrEZ. (Note the commend about rand.Seed.)
Since this still shows up in Google's top results for Golang random string generation, I wanted to share what I have been working with.
Here is the solution I am using:
package main
import (
"fmt"
"strings"
"time"
)
var (
opts = strings.Split("option1,option2,option3", ",")
start = time.Now()
)
func main() {
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
}
func getRandomOpt() string {
len := len(opts)
n := uint32(0)
if len > 0 {
n = getRandomUint32() % uint32(len)
}
return opts[n]
}
func getRandomUint32() uint32 {
x := time.Now().UnixNano()
return uint32((x >> 32) ^ x)
}
And results:
option2 665ns
option1 41.406µs
option1 44.817µs
option3 47.329µs
option1 49.725µs
option3 52µs
option2 54.393µs
option2 56.798µs
option1 59.098µs
Source wise, I copied getRandomUint32() from fastrand: https://github.com/valyala/fastrand
And the solution proposed above. Performance isn't all that different, but I wanted to share results.
package main
import (
"fmt"
"math/rand"
"strings"
"time"
)
var (
opts = strings.Split("option1,option2,option3", ",")
start = time.Now()
)
func main() {
rand.Seed(start.Unix())
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
fmt.Println(getRandomOpt(), time.Since(start))
}
func getRandomOpt() string {
return opts[rand.Intn(len(opts))]
}
And results:
option3 11.865µs
option2 48.415µs
option3 52.809µs
option1 55.536µs
option3 58.191µs
option3 60.793µs
option1 63.391µs
option2 65.982µs
option2 68.601µs
These results were only run a few times locally and I grabbed what appeared to be the median result. There is certainly more work to be done in terms of iterations and whatnot, but I just wanted to share what I have.
Related
I'm expecting these two time.Time instances are the same. But, I'm not sure why I got the compare result is false.
package main
import (
"fmt"
"time"
)
func main() {
t := int64(1497029400000)
locYangon, _ := time.LoadLocation("Asia/Yangon")
dt := fromEpoch(t).In(locYangon)
locYangon2, _ := time.LoadLocation("Asia/Yangon")
dt2 := fromEpoch(t).In(locYangon2)
fmt.Println(dt2 == dt)
}
func fromEpoch(jsDate int64) time.Time {
return time.Unix(0, jsDate*int64(time.Millisecond))
}
Playground
If I change "Asia/Yangon" to "UTC", they are the same.
package main
import (
"fmt"
"time"
)
func main() {
t := int64(1497029400000)
locYangon, _ := time.LoadLocation("UTC")
dt := fromEpoch(t).In(locYangon)
locYangon2, _ := time.LoadLocation("UTC")
dt2 := fromEpoch(t).In(locYangon2)
fmt.Println(dt2 == dt)
}
func fromEpoch(jsDate int64) time.Time {
return time.Unix(0, jsDate*int64(time.Millisecond))
}
Playground
Note: I'm aware of Equal method (in fact, I fixed with Equal method.) But after more testing, I found some interesting case which is "UTC" location vs "Asia/Yangon" location. I'm expecting either both equal or both not equal.
Update: Add another code snippet with "UTC".
Update2: Update title to be more precise (I hope it will help to avoid duplication)
LoadLocation seems to return a pointer to a new value every time.
Anyway, the good way to compare dates is Equal:
fmt.Println(dt2.Equal(dt))
Playground: https://play.golang.org/p/9GW-LSF0wg.
I'm using C# my entire life and now trying out GO. How do I find the lower time value between two time structs?
import (
t "time"
"fmt"
)
func findTime() {
timeA, err := t.Parse("01022006", "08112016")
timeB, err := t.Parse("01022006", "08152016")
Math.Min(timeA.Ticks, timeB.Ticks) // This is C# code but I'm looking for something similar in GO
}
You can use the Time.Before method to test if a time is before another:
timeA, err := time.Parse("01022006", "08112016")
timeB, err := time.Parse("01022006", "08152016")
var min time.Time
if timeA.Before(timeB) {
min = timeA
} else {
min = timeB
}
I wrote a piece of code to illustrate the standard command grep in Go, but the speed is
far behind it, could someone give me any advances? here is the code:
package main
import (
"bufio"
"fmt"
"log"
"os"
"strings"
"sync"
)
func parse_args() (file, pat string) {
if len(os.Args) < 3 {
log.Fatal("usage: gorep2 <file_name> <pattern>")
}
file = os.Args[1]
pat = os.Args[2]
return
}
func readFile(file string, to chan<- string) {
f, err := os.Open(file)
if err != nil {
log.Fatal(err)
}
defer f.Close()
freader := bufio.NewReader(f)
for {
line, er := freader.ReadBytes('\n')
if er == nil {
to <- string(line)
} else {
break
}
}
close(to)
}
func grepLine(pat string, from <-chan string, result chan<- bool) {
var wg sync.WaitGroup
for line := range from {
wg.Add(1)
go func(l string) {
defer wg.Done()
if strings.Contains(l, pat) {
result <- true
}
}(string(line))
}
wg.Wait()
close(result)
}
func main() {
file, pat := parse_args()
text_chan := make(chan string, 10)
result_chan := make(chan bool, 10)
go readFile(file, text_chan)
go grepLine(pat, text_chan, result_chan)
var total uint = 0
for r := range result_chan {
if r == true {
total += 1
}
}
fmt.Printf("Total %d\n", total)
}
The time in Go:
>>> time gogrep /var/log/task.log DEBUG
Total 21089
real 0m0.156s
user 0m0.156s
sys 0m0.015s
The time in grep:
>>> time grep DEBUG /var/log/task.log | wc -l
21089
real 0m0.069s
user 0m0.046s
sys 0m0.064s
For an easily reproducible benchmark, I counted the number of occurences of the text "and" in Shakespeare.
gogrep:
$ go build gogrep.go && time ./gogrep /home/peter/shakespeare.txt and
Total 21851
real 0m0.613s
user 0m0.651s
sys 0m0.068s
grep:
$ time grep and /home/peter/shakespeare.txt | wc -l
21851
real 0m0.108s
user 0m0.107s
sys 0m0.014s
petergrep:
$ go build petergrep.go && time ./petergrep /home/peter/shakespeare.txt and
Total 21851
real 0m0.098s
user 0m0.092s
sys 0m0.008s
petergrep is written in Go. It's fast.
package main
import (
"bufio"
"bytes"
"fmt"
"log"
"os"
)
func parse_args() (file, pat string) {
if len(os.Args) < 3 {
log.Fatal("usage: petergrep <file_name> <pattern>")
}
file = os.Args[1]
pat = os.Args[2]
return
}
func grepFile(file string, pat []byte) int64 {
patCount := int64(0)
f, err := os.Open(file)
if err != nil {
log.Fatal(err)
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
if bytes.Contains(scanner.Bytes(), pat) {
patCount++
}
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, err)
}
return patCount
}
func main() {
file, pat := parse_args()
total := grepFile(file, []byte(pat))
fmt.Printf("Total %d\n", total)
}
Data: Shakespeare: pg100.txt
Go regular expressions are fully utf-8 and I think that has some overhead. They also have a different theoretical basis meaning they will always run in a time proportional to the length of the input. It is noticeable that Go regexps just aren't as fast as the pcre regexp in use by other languages. If you look at the benchmarks game shootouts for the regexp test you'll see what I mean.
You can always use the pcre library directly if you want a bit more speed though.
A datapoint on the relevance of UTF-8 in regexp parsing: I've a long-used custom perl5 script for source grepping. I recently modified it to support UTF-8 so it could match fancy golang symbol names. It ran a FULL ORDER OF MAGNITUDE slower in repeated tests. So while golang regexp's do pay a price for the predictability of it's runtime, we also have to factor UTF-8 handling into the equation.
Is there a way to scan a big.Int directly from the standard input in Go? Right now I'm doing this:
package main
import (
"fmt"
"math/big"
)
func main() {
w := new(big.Int)
var s string
fmt.Scan(&s)
fmt.Sscan(s, w)
fmt.Println(w)
}
I also could have used .SetString. But, is there a way to Scan the big.Int directly from the standard input without scanning a string or an integer first?
For example,
package main
import (
"fmt"
"math/big"
)
func main() {
w := new(big.Int)
n, err := fmt.Scan(w)
fmt.Println(n, err)
fmt.Println(w.String())
}
Input (stdin):
295147905179352825857
Output (stdout):
1 <nil>
295147905179352825857
As far as I know - no, there's no other way. In fact, what you've got is the default example they have for scanning big.Int in the documentation.
package main
import (
"fmt"
"log"
"math/big"
)
func main() {
// The Scan function is rarely used directly;
// the fmt package recognizes it as an implementation of fmt.Scanner.
i := new(big.Int)
_, err := fmt.Sscan("18446744073709551617", i)
if err != nil {
log.Println("error scanning value:", err)
} else {
fmt.Println(i)
}
}
You can see the relevant section here - http://golang.org/pkg/math/big/#Int.Scan
How do you time a function in Go and return its runtime in milliseconds?
Go's defer makes this trivial.
In Go 1.x, define the following functions:
func trace(s string) (string, time.Time) {
log.Println("START:", s)
return s, time.Now()
}
func un(s string, startTime time.Time) {
endTime := time.Now()
log.Println(" END:", s, "ElapsedTime in seconds:", endTime.Sub(startTime))
}
After that, you get Squeaky Clean one line elapsed time log messages:
func someFunction() {
defer un(trace("SOME_ARBITRARY_STRING_SO_YOU_CAN_KEEP_TRACK"))
//do a bunch of stuff here...
}
The clever magic is that the trace() is called at the beginning of the function, but the un() is deferred to the end. It's not atomic-clock accurate, due to the log statements, but if you need more accuracy, this kind of pattern is one of Go's marshmallowy good strengths.
EDIT:
This answer originally used legacy time package API. Reproduced here for historical value only:
For use w/ Go versions prior to 12-01-2011 weekly:
func trace(s string) (string, int64) {
log.Println("START:", s)
return s, time.Nanoseconds()
}
func un(s string, startTime int64) {
endTime := time.Nanoseconds()
log.Println(" END:", s, "ElapsedTime in seconds:", float32(endTime-startTime)/1E9)
}
Use the Go testing package to benchmark the function. For example,
package main
import (
"fmt"
"testing"
)
// the function to be benchmarked
func Function(n int) int64 {
n64 := int64(n)
return n64 * n64
}
func BenchmarkFunction(b *testing.B) {
n := 42
for i := 0; i < b.N; i++ {
_ = Function(n)
}
}
func main() {
br := testing.Benchmark(BenchmarkFunction)
fmt.Println(br)
}
Output:
500000000 4.22 ns/op
You can also use the Go gotest command to run benchmarks.
Another easy way can be:
import (
"fmt"
"time"
)
start := time.Now()
// some computation
elapsed := time.Since(start)
fmt.Println(elapsed)
which will output something like 359.684612ms
Perhaps you can also use a Duration (elapsed) for this...looks a little bit nicer.
func trace(s string) (string, time.Time) {
log.Printf("trace start: %s\n", s)
return s, time.Now()
}
func un(s string, startTime time.Time) {
elapsed := time.Since(startTime)
log.Printf("trace end: %s, elapsed %f secs\n", s, elapsed.Seconds())
}
There are several options for timestamping and timers in the time package. See the documentation here: http://golang.org/pkg/time/