2
\$\begingroup\$

I am new in Golang, and decided to create a function that could cater to my needs of reading an integer from stdin. I need the function to be as efficient and fast as possible.

package main
import(
    "fmt"
    "bufio"
    "os"
    "strconv"
)

type NoIntRead int

func (err *NoIntRead) Error() string{
    return fmt.Sprintf("No integer was read!")
}

var(
    inputreader = bufio.NewReader(os.Stdin)
    mybyteslice []byte = make([]byte,11)
)
func ReadInt() (int,error){
    var mybyte byte
    var myint int
    var err error
    var size int = 0
    for{
        mybyte,err = inputreader.ReadByte()
        if mybyte == '\n' || mybyte == ' ' || err != nil{
            if size == 0{
                myerr := NoIntRead(1)
                return 0,&myerr
            }
            mystring := string(mybyteslice[:size])
            myint,err = strconv.Atoi(mystring) 
            if err != nil{
                myerr := NoIntRead(1)
                return 0, &myerr
            }
            return myint,nil
        }
        mybyteslice[size] = mybyte
        size++
    }
}
func main(){
    var myint int
    var err error
    for{
        myint,err = ReadInt()
        if err != nil{
            fmt.Println(err)
            break;
        }
        fmt.Println(myint)
    }
}

Is there a more efficient way to read integers from stdin? If yes, I would be more than grateful if someone could point me into the right direction.

\$\endgroup\$
1
\$\begingroup\$

There's the logical answer which is to use fmt.Scan to read StdIn (See https://golang.org/pkg/fmt/#Scan ):

func main(){
    var myint int
    for {
        if _, err := fmt.Scan(&myint); err != nil {
            fmt.Printf("Unable to scan: %v", err)
            break
        }
        fmt.Println(myint)
    }
}

If you're interested in better-performing options than that, I suggest writing up some benchmark tests and using those to improve the performance of the method. See benchmarking notes here: https://golang.org/pkg/testing/

\$\endgroup\$
1
\$\begingroup\$

As suggested by rolfl you should do Benchmarks on different approaches. This is the only way to tell, if you actually improved on your function.

There are a few points you can improve (or check if they actually improve your case) that I can share from experience:

1) currently you are converting the bytes to string and then you are creating an integer from them. Since you already know there will be integers, use the binary package to do the transformation from bytes directly to integer:

order := binary.LittleEndian
myint := int(order.Uint64(mybyteslice))

Note: this is about 10 times faster than any string/scan operation you can do.

2) Have you checked ReadBytes function of the inputreader? That could probably eliminate your for loop and thus also eliminate the memory allocations you have each time you add an item to mybyteslice.

3) This probably should be the first point because it is the most important: check out the pprof tool to investigate your code. For this you definitly need to write Benchmarks or generate load for your code another way. Then check what takes time in your code and minimize your allocations. Good places to start with pprof are this video and the very good article Debugging performance issues in go making a lot of suggestions.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.