execpool

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 18, 2021 License: MIT Imports: 6 Imported by: 0

README

ExecPool

License Build Coverage Status Go Report Card GoDoc Release

Why? Sometimes when you implement Go services you have to integrate with third party command line tools. You can do it by simply using exec.Command but the problem with this approach is that your service has to wait while a new process is being loaded into the memory and started. Sometimes this can drastically increase the latency of your service. ExecPool works similarly to FastCGI but it can wrap any regular process. It spins up a given number of processes in advance and when it's time to handle a request from the user your service just attaches stdin to an existing process from the pool. Basically the execpool helps you trade memory for latency.

Usage

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os/exec"
	"strings"

	"github.com/hexdigest/execpool"
)

func main() {
	cmd := exec.Command("grep", "none")

	//spin up 100 processes of grep
	pool, err := execpool.New(cmd, 100)

	rc := pool.Exec(strings.NewReader("this makes sense\nthis is nonesense"))
	b, err := ioutil.ReadAll(rc)
	if err != nil {
		log.Fatalf("failed to read from stdout: %v", err)
	}

	// this is nonesense
	fmt.Println(string(b))
}

Benchmark

This benchmark compares "standard" approach with exec.Command and execpool.Pool by running grep 100 times. For heavier processes you can expect bigger difference.

make benchmark
goos: darwin
goarch: amd64
pkg: github.com/hexdigest/execpool
cpu: Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz
BenchmarkNew-8               100            941753 ns/op
BenchmarkCmd-8               100           2386990 ns/op

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Command

type Command struct {
	// contains filtered or unexported fields
}

Command is wrapper around exec.Cmd that implements io.Reader interface

func (*Command) Read

func (c *Command) Read(p []byte) (int, error)

Read implements io.Reader

type Pool

type Pool struct {
	// contains filtered or unexported fields
}

Pool of processes

func New

func New(cmd *exec.Cmd, processCount int) (*Pool, error)

New creates a new pool by spinning processCount copies of cmd

func (*Pool) Exec

func (p *Pool) Exec(stdin io.Reader) (stdout io.Reader)

Exec fetches a waiting process from the pool and attaches stdin to this process.

func (*Pool) ExecContext

func (p *Pool) ExecContext(ctx context.Context, stdin io.Reader) (stdout io.Reader)

ExecContext takes a waiting process from the pool and attaches stdin to it and returns a reader representing its stdout. When ctx id done the pool closes stdout and terminate the process.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL