Saya ingin berkontribusi dengan contoh sederhana dan penjelasan yang saya temukan berguna ketika saya harus mengatasi masalah ini sendiri.
Dalam jawaban ini Anda akan menemukan beberapa informasi tentang Python GIL (kunci juru bahasa global) dan contoh sederhana sehari-hari yang ditulis menggunakan multiprocessing.dummy plus beberapa tolok ukur sederhana.
Global Interpreter Lock (GIL)
Python tidak mengizinkan multi-threading dalam arti kata yang sebenarnya. Ini memiliki paket multi-threading, tetapi jika Anda ingin multi-thread untuk mempercepat kode Anda, maka biasanya bukan ide yang baik untuk menggunakannya.
Python memiliki konstruk yang disebut global interpreter lock (GIL). GIL memastikan bahwa hanya satu dari 'utas' Anda yang dapat dieksekusi pada satu waktu. Sebuah thread mendapatkan GIL, melakukan sedikit pekerjaan, lalu meneruskan GIL ke thread berikutnya.
Hal ini terjadi sangat cepat sehingga bagi mata manusia, sepertinya utas Anda berjalan paralel, tetapi mereka benar-benar hanya bergantian menggunakan inti CPU yang sama.
Semua operan GIL ini menambah biaya eksekusi. Ini berarti bahwa jika Anda ingin membuat kode Anda berjalan lebih cepat maka menggunakan paket threading sering bukan ide yang baik.
Ada alasan untuk menggunakan paket threading Python. Jika Anda ingin menjalankan beberapa hal secara bersamaan, dan efisiensi bukan masalah, maka itu benar-benar baik dan nyaman. Atau jika Anda menjalankan kode yang perlu menunggu sesuatu (seperti beberapa I / O) maka itu bisa masuk akal. Tetapi pustaka threading tidak akan membiarkan Anda menggunakan core CPU tambahan.
Multi-threading dapat dialihdayakan ke sistem operasi (dengan melakukan multi-pemrosesan), dan beberapa aplikasi eksternal yang memanggil kode Python Anda (misalnya, Spark atau Hadoop ), atau beberapa kode yang panggilan kode Python Anda (misalnya: Anda bisa minta kode Python Anda memanggil fungsi C yang melakukan hal-hal multi-threaded yang mahal).
Mengapa Ini Penting?
Karena banyak orang menghabiskan banyak waktu untuk mencari kemacetan dalam kode multi-threaded Python mewah mereka sebelum mereka mengetahui apa itu GIL.
Setelah informasi ini jelas, inilah kode saya:
#!/bin/python
from multiprocessing.dummy import Pool
from subprocess import PIPE,Popen
import time
import os
# In the variable pool_size we define the "parallelness".
# For CPU-bound tasks, it doesn't make sense to create more Pool processes
# than you have cores to run them on.
#
# On the other hand, if you are using I/O-bound tasks, it may make sense
# to create a quite a few more Pool processes than cores, since the processes
# will probably spend most their time blocked (waiting for I/O to complete).
pool_size = 8
def do_ping(ip):
if os.name == 'nt':
print ("Using Windows Ping to " + ip)
proc = Popen(['ping', ip], stdout=PIPE)
return proc.communicate()[0]
else:
print ("Using Linux / Unix Ping to " + ip)
proc = Popen(['ping', ip, '-c', '4'], stdout=PIPE)
return proc.communicate()[0]
os.system('cls' if os.name=='nt' else 'clear')
print ("Running using threads\n")
start_time = time.time()
pool = Pool(pool_size)
website_names = ["www.google.com","www.facebook.com","www.pinterest.com","www.microsoft.com"]
result = {}
for website_name in website_names:
result[website_name] = pool.apply_async(do_ping, args=(website_name,))
pool.close()
pool.join()
print ("\n--- Execution took {} seconds ---".format((time.time() - start_time)))
# Now we do the same without threading, just to compare time
print ("\nRunning NOT using threads\n")
start_time = time.time()
for website_name in website_names:
do_ping(website_name)
print ("\n--- Execution took {} seconds ---".format((time.time() - start_time)))
# Here's one way to print the final output from the threads
output = {}
for key, value in result.items():
output[key] = value.get()
print ("\nOutput aggregated in a Dictionary:")
print (output)
print ("\n")
print ("\nPretty printed output: ")
for key, value in output.items():
print (key + "\n")
print (value)