Threads OK
This commit is contained in:
parent
65b8e4294d
commit
a2c3f22f1d
@ -25,10 +25,9 @@
|
|||||||
|
|
||||||
* Program NOEXPORT :noexport:
|
* Program NOEXPORT :noexport:
|
||||||
|
|
||||||
|
|
||||||
14:00-14:30 : Supercomputers
|
14:00-14:30 : Supercomputers
|
||||||
14:30-15:30 : Parallelism
|
14:30-15:30 : Parallelism
|
||||||
15:45-17:30 : OpenMP/MPI
|
15:45-17:30 : MPI / OpenMP
|
||||||
|
|
||||||
09:00-10:30 : Presentation IRP + QP
|
09:00-10:30 : Presentation IRP + QP
|
||||||
Pour IRPF90, je peux faire une presentation assez generale.
|
Pour IRPF90, je peux faire une presentation assez generale.
|
||||||
@ -656,7 +655,7 @@ sys 0m3.172s
|
|||||||
- Processes interact only through system-provided communication mechanisms
|
- Processes interact only through system-provided communication mechanisms
|
||||||
- Fork: creates a copy of the current process
|
- Fork: creates a copy of the current process
|
||||||
- Exec: switches to running another binary executable
|
- Exec: switches to running another binary executable
|
||||||
- Spawn: =Fork=, then =exec= the child
|
- Spawn: =Fork=, =exec= the child and =wait= for its termination
|
||||||
*** Thread
|
*** Thread
|
||||||
- Exist as subsets of a process
|
- Exist as subsets of a process
|
||||||
- Context switching between threads is fast
|
- Context switching between threads is fast
|
||||||
@ -783,9 +782,8 @@ def main():
|
|||||||
# Read data from the child
|
# Read data from the child
|
||||||
print("Reading from the child")
|
print("Reading from the child")
|
||||||
s = r.read()
|
s = r.read()
|
||||||
r.close()
|
|
||||||
print("Read '%s' from the child"%(s))
|
print("Read '%s' from the child"%(s))
|
||||||
|
r.close() ; os.wait()
|
||||||
#+end_src
|
#+end_src
|
||||||
#+LATEX: \end{column}
|
#+LATEX: \end{column}
|
||||||
#+LATEX: \begin{column}{0.4\textwidth}
|
#+LATEX: \begin{column}{0.4\textwidth}
|
||||||
@ -813,7 +811,6 @@ def main():
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
||||||
#+end_src
|
#+end_src
|
||||||
#+LATEX: \end{column}
|
#+LATEX: \end{column}
|
||||||
#+LATEX: \begin{column}{0.4\textwidth}
|
#+LATEX: \begin{column}{0.4\textwidth}
|
||||||
@ -1172,8 +1169,7 @@ $ python pi_server_python.py &
|
|||||||
|
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
* Message Passing Interface (MPI) :noexport:
|
||||||
* Message Passing Interface (MPI)
|
|
||||||
|
|
||||||
** Message Passing Interface
|
** Message Passing Interface
|
||||||
|
|
||||||
@ -1515,7 +1511,7 @@ if __name__ == "__main__": main()
|
|||||||
#+LATEX: \begin{columns}
|
#+LATEX: \begin{columns}
|
||||||
#+LATEX: \begin{column}{0.6\textwidth}
|
#+LATEX: \begin{column}{0.6\textwidth}
|
||||||
#+begin_src text
|
#+begin_src text
|
||||||
$ mpiexec -n 8 python mpi_pi_v2.py 100000000
|
$ mpiexec -n 4 python mpi_pi_v2.py 100000000
|
||||||
0 0.7853981783959749
|
0 0.7853981783959749
|
||||||
Result = 3.1415926535901777
|
Result = 3.1415926535901777
|
||||||
2 0.7853981583983196
|
2 0.7853981583983196
|
||||||
@ -1529,6 +1525,155 @@ Result = 3.1415926535901777
|
|||||||
#+LATEX: \end{column}
|
#+LATEX: \end{column}
|
||||||
#+LATEX: \end{columns}
|
#+LATEX: \end{columns}
|
||||||
|
|
||||||
|
* Multi-threading
|
||||||
|
** Processes /vs/ threads
|
||||||
|
|
||||||
|
*** Process
|
||||||
|
- Has its own memory address space
|
||||||
|
- Context switching between processes is slow
|
||||||
|
- Processes interact only through system-provided communication mechanisms
|
||||||
|
- Fork: creates a copy of the current process
|
||||||
|
- Exec: switches to running another binary executable
|
||||||
|
- Spawn: =Fork=, then =exec= the child
|
||||||
|
*** Thread
|
||||||
|
- Exist as subsets of a process
|
||||||
|
- Context switching between threads is fast
|
||||||
|
- Share the same memory address space : interact via shared memory
|
||||||
|
|
||||||
|
** Threads
|
||||||
|
#+LATEX: \begin{columns}
|
||||||
|
#+LATEX: \begin{column}{0.5\textwidth}
|
||||||
|
#+ATTR_LATEX: :height 0.5\textheight
|
||||||
|
[[./smp.png]]
|
||||||
|
#+LATEX: \end{column}
|
||||||
|
#+LATEX: \begin{column}{0.5\textwidth}
|
||||||
|
- Concurrent programming
|
||||||
|
- Graphical user interfaces (progress bars, ...)
|
||||||
|
- Asynchronous I/O
|
||||||
|
- Standard library: POSIX threads (pthreads)
|
||||||
|
#+LATEX: \end{column}
|
||||||
|
#+LATEX: \end{columns}
|
||||||
|
|
||||||
|
*** Communication time
|
||||||
|
- Low latency network latency : \sim 1.2 microsecond
|
||||||
|
- Random memory access : \sim 0.1 microsecond
|
||||||
|
|
||||||
|
** Threads example (Python)
|
||||||
|
|
||||||
|
#+begin_src python :tangle Codes/thread_python.py
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
class test:
|
||||||
|
def __init__(self, Nthreads):
|
||||||
|
self.Nthreads = Nthreads
|
||||||
|
self.data = [ i for i in range(Nthreads) ]
|
||||||
|
|
||||||
|
def run_thread(self, j):
|
||||||
|
self.data[j] = 0
|
||||||
|
time.sleep(j)
|
||||||
|
self.data[j] = j
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Threads example (Python)
|
||||||
|
|
||||||
|
#+begin_src python :tangle Codes/thread_python.py
|
||||||
|
def run(self):
|
||||||
|
thread = [ None ] * self.Nthreads
|
||||||
|
t0 = time.time()
|
||||||
|
print(self.data)
|
||||||
|
for i in range(self.Nthreads):
|
||||||
|
thread[i] = threading.Thread( target=self.run_thread, args=(i,) )
|
||||||
|
thread[i].start()
|
||||||
|
for i in range(self.Nthreads):
|
||||||
|
thread[i].join()
|
||||||
|
print(time.time()-t0, "seconds. ", self.data)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
t = test(4)
|
||||||
|
t.run()
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
-------------------
|
||||||
|
#+begin_src text
|
||||||
|
$ python thread_python.py
|
||||||
|
[0, 1, 2, 3]
|
||||||
|
0.0009775161743164062 seconds. [0, 0, 0, 0]
|
||||||
|
1.0018701553344727 seconds. [0, 1, 0, 0]
|
||||||
|
2.003377676010132 seconds. [0, 1, 2, 0]
|
||||||
|
3.004056930541992 seconds. [0, 1, 2, 3]
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Computation of \pi with threads in Python
|
||||||
|
|
||||||
|
#+begin_src python :tangle Codes/pi_thread_python.py
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import os, sys, threading
|
||||||
|
from random import random, seed
|
||||||
|
from math import sqrt
|
||||||
|
|
||||||
|
NMAX = 10000000 # Nb of MC steps/process
|
||||||
|
error_threshold = 1.0e-4 # Stopping criterion
|
||||||
|
|
||||||
|
class pi_calculator:
|
||||||
|
def __init__(self, Nthreads):
|
||||||
|
self.Nthreads= Nthreads
|
||||||
|
self.results = []
|
||||||
|
self.lock = threading.Lock()
|
||||||
|
|
||||||
|
def compute_pi(self):
|
||||||
|
result = 0.
|
||||||
|
for i in range(NMAX): # Loop NMAX times
|
||||||
|
x,y = random(), random() # Draw 2 random numbers x and y
|
||||||
|
if x*x + y*y <= 1.: # Check if (x,y) is in the circle
|
||||||
|
result += 1
|
||||||
|
with self.lock:
|
||||||
|
self.results.append(4.* float(result)/float(NMAX))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Computation of \pi with threads in Python
|
||||||
|
|
||||||
|
#+begin_src python :tangle Codes/pi_thread_python.py
|
||||||
|
def run(self):
|
||||||
|
thread = [None] * self.Nthreads
|
||||||
|
for i in range(self.Nthreads):
|
||||||
|
thread[i] = threading.Thread( target=self.compute_pi, args=() )
|
||||||
|
thread[i].start()
|
||||||
|
print("All threads started")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
for i in range(self.Nthreads):
|
||||||
|
thread[i].join()
|
||||||
|
N = len(self.results)
|
||||||
|
average = sum(self.results)/N # Compute average
|
||||||
|
if N > 2: # Compute variance
|
||||||
|
l = [ (x-average)*(x-average) for x in self.results ]
|
||||||
|
variance = sum(l)/(N-1.)
|
||||||
|
else:
|
||||||
|
variance = 0.
|
||||||
|
error = sqrt(variance)/sqrt(N) # Compute error
|
||||||
|
print("%f +/- %f %d"%(average, error, N))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Computation of \pi with threads in Python
|
||||||
|
|
||||||
|
#+begin_src python :tangle Codes/pi_thread_python.py
|
||||||
|
if N > 2 and error < error_threshold: # Stopping condition
|
||||||
|
return
|
||||||
|
|
||||||
|
for i in range(self.Nthreads):
|
||||||
|
thread[i] = threading.Thread( target=self.compute_pi, args=() )
|
||||||
|
thread[i].start()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
calc = pi_calculator(4)
|
||||||
|
calc.run()
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Note: Inefficient in Python because of the Global Interpreter Lock
|
||||||
|
(GIL), but you got the idea.
|
||||||
|
|
||||||
* OpenMP
|
* OpenMP
|
||||||
|
|
||||||
* Exercises
|
* Exercises
|
||||||
|
Loading…
Reference in New Issue
Block a user