Multithreading-Golang

THREAD - Allows us to do parallel computing

  • On every program there is parallel and sequential parts and the sequential part acts as the bootleneck
  • AMDAHLS Law - Gives relationship between parallel part and sequential parts

  GUSTAFSONS LAW

  • Increasing the problem size to get linear growth with parralelism
  • Parallel programing does not work well when you have only 1 processor or 1 core.

USING THREADS

PROCESSES

  • Isolated units of work that do not affect one another in the event of one crashing

  • They are heavy weight because they need their own memory allocation.

  • They take a while to create and consume a lot of memory

  • C++ uses FORK

  • Golang at the moment does not handle processes as efficiently as other languages like C++

  • Golang thrives on threading

  • A THREAD solves the issues that we have with processes.

  • A thread does not allocate new memory space but allows threads to access the same memory space after spawning

DRAWING ON THE SAME PAGE!!
  • A thread does however gives you isolation

GREAN THREAD

  • This is a more efficient thread.

  • Threading is based on swapping out jobs on idle so that there is no blocking, this is called CONTEXT SWITCH and it has some overhead 

  • This results in wasted CPU cycles

  • A green thread reduces the context switch overhead

  • The context switch is negligible when a program has very few threads

  • The more threads the more context switch routines

  • A normal thread is a kernel level thread (OS level)

  • A green thread is a user level thread. The program itself determines which thread to run

  • You can have maple green threads in 1 normal thread

  • With this strategy the kernel does not need to get involved in context switching.

  • Golang uses a hybrid system

  • The 1 disadvantage is for 1 green thread to cause other threads to wait for its IO OPERATION from a kernel Thread

THREAD SYNCRONISATION

  • We use muteness to lock thread execution and avoid race conditions
  • We can lock and unlock the Read Operations and the write operations separately.
  • Lock.RLock, Lock.RUnlock
  • The lock function is the writer lock
  • Lock.Lock

UNDERSTANDING WAITGROUPS

  • Lets us synchronize amoung multiple threads
  • These are sub-threads to a main thread that coordinates all activity
  • OPERATIONS
    • Add( int ) - Increments the group
    • Wait( ) - Instructs the wait group to wait for the children to finish
    • Done( ) - Called by each thread when finished.
var (
  matches []string
  waitgroup = sync.WaitGroup{}
  lock = sync.Mutex{}
)

func main() {
  waitgroup.Add(1)
  go filesearch("/projects/", "README.md")
  waitgroup.Wait()
  for _, file := range matches {
    fmt.Println("Matched file"file)
  }
}

CHANNELING AND PIPELINES

  • These are chained executions based on channels THREAD POOLS
  • This follows Master thread to Slave threads
  • Master and worker needs to communicate d

CONDITION VARIABLES

  • Tool that is available to allow more advanced synchronization amongst threads

  • Builds on the functionality of a mutex

  • You need a mutex to initialize a condition variable

  • In addition to locking a variable during manipulation on one thread, a condition variable ensures that unsafe procedures are not performed on variables e.g deduct 20 from a variable that has 10

  • During lock we check for conditions

  • If condition is not met, the thread goes into a wait state

  • There is a broadcast that happens when the variable is updated so that all threads that are waiting can be notified.

  • SIGNAL - Only wakes up just 1 thread

  • BROADCAST - Wakes up all the threads that were waiting

CONDITIONED THREAD

lock.Lock()
for money-20 < 0 {
  moneyDeposited.Wait()
}

SIGNALLING THREAD
lock.Lock()
money += 10
moneyDeposited.Signal()

DEADLOCKS

  • This is when resources lock dependancies and end up waiting indefinitely for each other.

  • To avoid this we can use a lock id to create a hierachy of locks