- Watch The Video Here: https://youtu.be/WPeNqnYV11o
- The code is available here
High Performance Data Science (HPDS)
https://taudata.blogspot.com
HPDS-02: Pendahuluan Thread Programming di Python
https://taudata.blogspot.com/2022/04/hpds-02.html
(C) Taufik Sutanto
Program, Thread, & Process¶
Proses di Operating System¶
- Program adalah entitas statis di komputer kita.
- Saat program dijalankan ia berubah menjadi sebuah proses (terkadang disebut juga sebagai Task).
- Sehingga proses adalah sebuah program yang sedang dijalankan.
- Satu program dapat terdiri dari beberapa proses.
- Saat ada beberapa prosesor, maka proses dapat dijalankan secara parallel.
- Jika hanya ada 1 prosesor, proses dapat dijalankan bergantian (dengan sangat cepat) seolah-olah semua berjalan berbarengan.
- Proses memiliki (resources terpisah):
- Code segment - text section
- Data - global variable
- Stack - variabel lokal dan fungsi-fungsi
- Heap - variabel/class yang dialokasikan secara dinamis
- State - ready, waiting, running.
- process identifier, prioritas, dsb.
Thread di Operating System¶
- Thread adalah bagian (unit of execution) dari sebuah proses.
- Dengan kata lain thread adalah subset dari proses.
- Proses selalu dimulai dengan single (primary) thread.
- Primary thread kemudian dapat membuat thread lain.
- Thread memiliki shared resources memory, data, resources, files dll.
Contoh:¶
- Pada komputer kita Microsoft Word dan misal browser Chrome adalah contoh proses.
- Di microsot word saat kita mengetik, maka ms word juga melakukan autosave dan autocorrect. mengetik (editing), autosave, dan autocorrect adalah contoh thread.
Kelebihan Melakukan Threading Programming¶
- Program dengan multi-thread dapat berjalan dengan cepat karena thread dapat dijalankan di CPU yang berbeda.
- Program dengan multi-thread masih responsive terhadap input dari user.
- Thread-thread yang ada dapat mengakses variable global.
- Perubahan nilai variable global oleh satu thread akan Valid untuk thread yang lain.
- Thread dapat memiliki variabel lokal.
I/O VS Komputasi¶
- Secara umum proses yang membutuhkan banyak komputasi (dan sedikit Input-Output I/O) akan diuntungkan dari pemrograman parallel (gambar).
- I/O bound: komunikasi via internet, harddisk, printer, dsb.
- Proses yang membutuhkan banyak komputasi: Math, Stats, Physiscs, Machine Learning, AI.
- image source: https://realpython.com/python-concurrency/
Module Thread di Python¶
- Thread (deprecated di Python 3, renamed jadi _Thread )
- threading
Contoh Sederhana:¶
- Sebaiknya dijalankan di terminal.
- if name == "main": wajib ada di semua code python yang menggunakan thread/parallel programming.
- Keterangan tentang main : https://www.youtube.com/watch?v=IaKbhwLs0kw
In [ ]:
# -*- coding: utf-8 -*-
"""
Created on Mon Dec 7 08:59:27 2020
Contoh Threading sederhana di Python 3
@author: Taufik Sutanto
"""
import time
from threading import Thread
def sleeper(i):
nSleep = 3
print("thread {} sleeps for {} seconds".format(i, nSleep))
time.sleep(nSleep)
print("thread %d woke up" % i)
if __name__ == "__main__":
for i in range(10):
t = Thread(target=sleeper, args=(i,))
t.start()
In [ ]:
import threading
def print_cube(num):
print("Cube: {}".format(num * num * num))
def print_square(num):
print("Square: {}".format(num * num))
if __name__ == "__main__":
# creating thread
t1 = threading.Thread(target=print_square, args=(10,))
t2 = threading.Thread(target=print_cube, args=(10,))
t1.start() # starting thread 1
t2.start() # starting thread 2
t1.join() # wait until thread 1 is completely executed
t2.join() # wait until thread 2 is completely executed
# both threads completely executed
print("Done!")
In [ ]:
import requests
import time
def download_site(url, session):
with session.get(url) as response:
print(f"Read {len(response.content)} from {url}")
def download_all_sites(sites):
with requests.Session() as session:
for url in sites:
download_site(url, session)
if __name__ == "__main__":
sites = [
"https://www.detik.com",
"https://kompas.com",
] * 80
start_time = time.time()
download_all_sites(sites)
duration = time.time() - start_time
print(f"Downloaded {len(sites)} in {duration} seconds")
Keterangan Code¶
- Variable "sites" adalah list dengan 2 URL, tapi x 80. Jadi total 160. Ingat sifat perkalian dengan List.
- Fungsi download_site() mengunduh semua URL yang ada di list sites lalu menyetak (print) ukuran/size.
- download_all_sites() membuat "Session" secara bergantian (successive/sequential) mengakses setiap URL.
- Terakhir mencetak berapa waktu yang dibutuhkan.
- Prosesnya seperti Gambar 1 diatas.
In [ ]:
import concurrent.futures
import requests
import threading
import time
thread_local = threading.local()
def get_session():
if not hasattr(thread_local, "session"):
thread_local.session = requests.Session()
return thread_local.session
def download_site(url):
session = get_session()
with session.get(url) as response:
print(f"Read {len(response.content)} from {url}")
def download_all_sites(sites):
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
executor.map(download_site, sites)
if __name__ == "__main__":
sites = [
"https://detik.com",
"https://kompas.com",
] * 80
start_time = time.time()
download_all_sites(sites)
duration = time.time() - start_time
print(f"Downloaded {len(sites)} in {duration} seconds")
Keterangan Code diatas¶
- Ketika menambahkan threading struktur umumnya sama, hanya ada beberapa modifikasi:
- Fungsi _download_allsites:
- ThreadPoolExecutor = Thread + Pool + Executor.
- Object Pool menciptakan a pool of threads (beberapa threads),setiap thread dapat berjalan parallel.
- Executor adalah bagian akan mengendalikan (control) bagaimana dan kapan setiap threads di pool akan dijalankan (run).
- ThreadPoolExecutor secara automatis mengatur menciptakan thread, menjalankan, dan menghabus/bebaskan thread.
- Metode .map() kemudian menjalankan fungsi dan inputnya pada setiap thread yang terbentuk.
- Image Source: https://realpython.com/python-concurrency/
Python Global Interpreter Lock (GIL)¶
- Mutex (Lock) yang memungkinkan suatu thread mengkontrol Python interpreter.
- Berarti hanya 1 thread yang berada dalam state/keadaan "execution" pada sembarang waktu. Sangat merugikan pada sistem dengan CPU>1.
- two different native threads of the same process can't run Python code at once.
Ilustrasi GIL di Python¶
In [ ]:
# -*- coding: utf-8 -*-
"""
Created on Mon Dec 7 12:59:23 2020
Ilustrasi Pengaruh GIL (single thread)
@author: Taufik Sutanto
"""
# single_threaded.py
import time
COUNT = 50000000
def countdown(n):
while n>0:
n -= 1
start = time.time()
countdown(COUNT)
end = time.time()
print('Time taken in seconds -', end - start)
In [ ]:
# -*- coding: utf-8 -*-
"""
Created on Mon Dec 7 12:59:23 2020
Ilustrasi Pengaruh GIL (Multi thread)
Akan menghasilkan waktu yang kurang lebih sama
@author: Taufik Sutanto
"""
import time
from threading import Thread
COUNT = 50000000
def countdown(n):
while n>0:
n -= 1
t1 = Thread(target=countdown, args=(COUNT//2,))
t2 = Thread(target=countdown, args=(COUNT//2,))
start = time.time()
t1.start()
t2.start()
t1.join()
t2.join()
end = time.time()
print('Time taken in seconds -', end - start)
In [ ]:
# -*- coding: utf-8 -*-
"""
Created on Mon Dec 7 13:03:30 2020
Contoh sederhana multi-processing
@author: Taufik Sutanto
"""
from multiprocessing import Pool
import time
COUNT = 50000000
def countdown(n):
while n>0:
n -= 1
if __name__ == '__main__':
pool = Pool(processes=2)
start = time.time()
r1 = pool.apply_async(countdown, [COUNT//2])
r2 = pool.apply_async(countdown, [COUNT//2])
pool.close()
pool.join()
end = time.time()
print('Time taken in seconds -', end - start)
Tidak ada komentar:
Posting Komentar
Relevant & Respectful Comments Only.