Concorrência e paralelismo em Go

Post on 06-May-2015

302 views 3 download

description

Palestra apresentada no DevCamp 2014, sobre concorrência e paralelismo em Go.

Transcript of Concorrência e paralelismo em Go

Concorrência e Paralelismo em Go

Francisco Souza @franciscosouza

what the f**rancisco?!

• Globo.com

• tsuru

• Go

Concorrência & Paralelismo

http://vimeo.com/49718712

Por que?

The free lunch is over

“Most classes of applications have enjoyed free and regular performance gains for several decades, even without releasing new versions or doing anything special...- Herb Sutter, 2005 ”

“Concurrency is not just for doing more things faster. It's for writing better code.

- Andrew Gerrand, 2014 ”

Threading

static  long  values_sum  =  0;  !int  main(void)  {     thrd_t  threads[NTHREADS];     long  i;     int  status;     for(i  =  0;  i  <  NTHREADS;  i++)  {       thrd_create(&threads[i],  sum,  (void  *)i);     }     for(i  =  0;  i  <  NTHREADS;  i++)  {       thrd_join(threads[i],  &status);     }     printf("%ld\n",  values_sum);  }

int  sum(void  *arg)  {     long  id  =  (long)arg;     int  i,  start,  end;     start  =  id  *  (N  /  NTHREADS  +  1);     end  =  start  +  (N  /  NTHREADS  +  1);     for(i  =  start;  i  <  end;  i++)  {       if(i  <  N)  {         mtx_lock(&mut);         values_sum  +=  i;         mtx_unlock(&mut);       }     }     return  thrd_success;  }

“Threading is a performance hack- Eric S. Raymond, 2003 ”

Communicating Sequential Processes

PROC  foo  (CHAN  INT  out!)          out  !  42  :  !PROC  bar  (CHAN  INT  in?)          INT  v:          SEQ                  in  ?  v  :

Em Go

• Processos = goroutines

• Canais = canais :)

goroutines ping-pongfunc  play(msg  string)  {     for  {       fmt.Println(msg)       time.Sleep(100e6)     }  }  !func  main()  {     go  play("ping")     go  play("pong")     time.Sleep(2e9)  }

Canais

type  Person  struct  {     Name  string  }  !type  Elevator  struct  {     number  int     people  chan  Person  }

Canaisfunc  main()  {     nPeople  :=  flag.Int("people",  100,  "Number  of  people")     nElevators  :=  flag.Int("elevators",  4,  "Number  of  elevators")     flag.Parse()     people  :=  make(chan  Person)     for  i  :=  0;  i  <  *nElevators;  i++  {       e  :=  NewElevator(i,  people)       e.Start()     }     for  i  :=  0;  i  <  *nPeople;  i++  {       name  :=  fmt.Sprintf("person  %d",  i+1)       people  <-­‐  Person{Name:  name}     }     close(people)  }

Canais

func  (e  *Elevator)  Start()  {     go  func()  {       for  p  :=  range  e.people  {         fmt.Printf("elevator  %d  transporting  %s.\n",  e.number,  p.Name)         time.Sleep(time.Duration((rand.Int()%5  +  1)  *  1e9))       }     }()  }

select

selectfunc  elevator(name  string)  chan<-­‐  Person  {     people  :=  make(chan  Person)     go  func()  {       for  p  :=  range  people  {         fmt.Printf("Elevator  %q  transporting  %q...\n",  name,  p.Name)         time.Sleep(1e9)       }     }()     return  people  }

select   people  :=  []Person{       {Name:  "Bob"},  {Name:  "Mary"},  {Name:  "Thomas"},       {Name:  "John"},  {Name:  "Peter"},  {Name:  "Ken"},       {Name:  "Patricia"},  {Name:  "Ane"},  {Name:  "Alice"},     }     elevator1  :=  elevator("social1")     elevator2  :=  elevator("social2")     elevator3  :=  elevator("vip")     for  _,  person  :=  range  people  {       select  {       case  elevator1  <-­‐  person:       case  elevator2  <-­‐  person:       case  elevator3  <-­‐  person:       }     }  

timeout

respChan  :=  make(chan  []byte)  go  doSomethingInTheNetwork(respChan)  select  {  case  data  :=  <-­‐respChan:          //  do  something  with  data  case  time.After(5  *  time.Second):          fmt.Println(“sloooow  connection”)  }

quit   go  func()  {       conn  :=  r.pool.Get()       defer  conn.Close()       var  payload  interface{}       var  err  error       for  payload  ==  nil  {         select  {         case  <-­‐quit:           return         default:           payload,  err  =  conn.Do("RPOP",  r.key())           if  err  !=  nil  {             errChan  <-­‐  err             return           }         }       }       payloadChan  <-­‐  payload.([]byte)     }()  

quit + timeout

  var  payload  []byte     select  {     case  payload  =  <-­‐payloadChan:     case  err  :=  <-­‐errChan:       return  nil,  err     case  <-­‐time.After(timeout):       close(quit)       return  nil,  &timeoutError{timeout:  timeout}     }

Sincronização

• Mutex

• RWMutex

• Once

• WaitGroup

Once

var  once  sync.Once  ...  once.Do(func()  {          CreateDatabasePoll("localhost:27107",  "db")  })

WaitGroup• “fork-join"

  var  containersGroup  sync.WaitGroup     for  _,  container  :=  range  containers  {       containersGroup.Add(1)       go  collectUnit(container,  units,  &containersGroup)     }     containersGroup.Wait()

Operações atômicas

Paralelismo: Implícito x Explícito

• Concorrência: forma como você estrutura seu programa

• Paralelismo: forma como você executa seu programa

GOMAXPROCS

• Nível de paralelismo definido em tempo de execução

• runtime.GOMAXPROCS

• env GOMAXPROCS

Concorrência e Paralelismo em GoFrancisco Souza @franciscosouza fss@corp.globo.com