Concurrency dengan Python - Kumpulan Untaian
Misalkan kita harus membuat sejumlah besar utas untuk tugas multithread kita. Ini akan menjadi paling mahal secara komputasi karena mungkin ada banyak masalah kinerja, karena terlalu banyak utas. Masalah utama bisa jadi pada throughput yang semakin terbatas. Kita dapat mengatasi masalah ini dengan membuat kumpulan utas. Kumpulan utas dapat didefinisikan sebagai grup utas yang sudah dibuat sebelumnya dan utas diam, yang siap untuk diberi pekerjaan. Membuat kumpulan utas lebih disukai daripada membuat contoh utas baru untuk setiap tugas ketika kita perlu melakukan banyak tugas. Kumpulan utas dapat mengelola eksekusi bersamaan dari sejumlah besar utas sebagai berikut -
Jika utas di kumpulan utas menyelesaikan eksekusinya, utas itu dapat digunakan kembali.
Jika utas dihentikan, utas lain akan dibuat untuk menggantikan utas itu.
Modul Python - Concurrent.futures
Pustaka standar Python menyertakan concurrent.futuresmodul. Modul ini ditambahkan dengan Python 3.2 untuk menyediakan antarmuka tingkat tinggi bagi pengembang untuk meluncurkan tugas-tugas asinkron. Ini adalah lapisan abstraksi di atas modul threading dan multiprocessing Python untuk menyediakan antarmuka untuk menjalankan tugas menggunakan kumpulan utas atau proses.
Di bagian selanjutnya, kita akan belajar tentang kelas-kelas yang berbeda dari modul concurrent.futures.
Kelas Pelaksana
Executoradalah kelas abstrak dari concurrent.futuresModul Python. Itu tidak dapat digunakan secara langsung dan kita perlu menggunakan salah satu dari subclass konkret berikut -
- ThreadPoolExecutor
- ProcessPoolExecutor
ThreadPoolExecutor - Subclass Beton
Ini adalah salah satu subclass konkret dari kelas Executor. Subclass menggunakan multi-threading dan kami mendapatkan kumpulan utas untuk mengirimkan tugas. Pangkalan ini menetapkan tugas ke utas yang tersedia dan menjadwalkannya untuk dijalankan.
Bagaimana cara membuat ThreadPoolExecutor?
Dengan bantuan dari concurrent.futures modul dan subkelas betonnya Executor, kita dapat dengan mudah membuat kumpulan utas. Untuk ini, kita perlu membangun fileThreadPoolExecutordengan jumlah utas yang kita inginkan di kumpulan. Secara default, jumlahnya adalah 5. Kemudian kita bisa mengirimkan tugas ke kumpulan thread. Ketika kitasubmit() tugas, kami kembali a Future. Objek Future memiliki metode yang disebutdone(), yang memberi tahu jika masa depan telah diselesaikan. Dengan ini, nilai telah ditetapkan untuk objek tertentu di masa mendatang. Saat tugas selesai, pelaksana kumpulan thread menetapkan nilai ke objek masa depan.
Contoh
from concurrent.futures import ThreadPoolExecutor
from time import sleep
def task(message):
sleep(2)
return message
def main():
executor = ThreadPoolExecutor(5)
future = executor.submit(task, ("Completed"))
print(future.done())
sleep(2)
print(future.done())
print(future.result())
if __name__ == '__main__':
main()
Keluaran
False
True
Completed
Dalam contoh di atas, a ThreadPoolExecutortelah dibuat dengan 5 utas. Kemudian tugas, yang akan menunggu selama 2 detik sebelum memberikan pesan, dikirimkan ke pelaksana kumpulan thread. Dilihat dari keluarannya, tugas tidak selesai sampai 2 detik, begitu juga panggilan pertama kedone()akan mengembalikan False. Setelah 2 detik, tugas selesai dan kita mendapatkan hasil di masa mendatang dengan memanggilresult() metode di atasnya.
Membuat instance ThreadPoolExecutor - Pengelola Konteks
Cara lain untuk membuat contoh ThreadPoolExecutoradalah dengan bantuan manajer konteks. Cara kerjanya mirip dengan metode yang digunakan dalam contoh di atas. Keuntungan utama menggunakan pengelola konteks adalah tampilannya bagus secara sintaksis. Instansiasi dapat dilakukan dengan bantuan kode berikut -
with ThreadPoolExecutor(max_workers = 5) as executor
Contoh
Contoh berikut dipinjam dari dokumen Python. Dalam contoh ini, pertama-tamaconcurrent.futuresmodul harus diimpor. Kemudian sebuah fungsi bernamaload_url()dibuat yang akan memuat url yang diminta. Fungsi kemudian membuatThreadPoolExecutordengan 5 utas di kolam. ItuThreadPoolExecutortelah digunakan sebagai manajer konteks. Kita bisa mendapatkan hasil masa depan dengan memanggilresult() metode di atasnya.
import concurrent.futures
import urllib.request
URLS = ['http://www.foxnews.com/',
'http://www.cnn.com/',
'http://europe.wsj.com/',
'http://www.bbc.co.uk/',
'http://some-made-up-domain.com/']
def load_url(url, timeout):
with urllib.request.urlopen(url, timeout = timeout) as conn:
return conn.read()
with concurrent.futures.ThreadPoolExecutor(max_workers = 5) as executor:
future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
for future in concurrent.futures.as_completed(future_to_url):
url = future_to_url[future]
try:
data = future.result()
except Exception as exc:
print('%r generated an exception: %s' % (url, exc))
else:
print('%r page is %d bytes' % (url, len(data)))
Keluaran
Berikut akan menjadi output dari skrip Python di atas -
'http://some-made-up-domain.com/' generated an exception: <urlopen error [Errno 11004] getaddrinfo failed>
'http://www.foxnews.com/' page is 229313 bytes
'http://www.cnn.com/' page is 168933 bytes
'http://www.bbc.co.uk/' page is 283893 bytes
'http://europe.wsj.com/' page is 938109 bytes
Penggunaan fungsi Executor.map ()
Python map()fungsi banyak digunakan dalam sejumlah tugas. Salah satu tugas tersebut adalah menerapkan fungsi tertentu ke setiap elemen dalam iterable. Demikian pula, kita dapat memetakan semua elemen iterator ke suatu fungsi dan mengirimkannya sebagai tugas independen ke luarThreadPoolExecutor. Pertimbangkan contoh skrip Python berikut untuk memahami cara kerja fungsinya.
Contoh
Dalam contoh di bawah ini, fungsi peta digunakan untuk menerapkan square() berfungsi untuk setiap nilai dalam larik nilai.
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import as_completed
values = [2,3,4,5]
def square(n):
return n * n
def main():
with ThreadPoolExecutor(max_workers = 3) as executor:
results = executor.map(square, values)
for result in results:
print(result)
if __name__ == '__main__':
main()
Keluaran
Skrip Python di atas menghasilkan output berikut -
4
9
16
25