HiveBrain v1.2.0
Get Started
← Back to all entries
patterngoMinor

Optimized Int Reader

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
intoptimizedreader

Problem

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.

Solution

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.

Code Snippets

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

Context

StackExchange Code Review Q#133806, answer score: 2

Revisions (0)

No revisions yet.