Rumah > Soal Jawab > teks badan
Python3.2中引入的concurrent非常的好用,只用几行代码就可以编写出线程池/进程池,并且计算型任务效率和mutiprocessing.pool提供的poll和ThreadPoll相比不分伯仲,而且在IO型任务由于引入了Future的概念效率要高数倍。
而threading的话还要自己维护相关的队列防止死锁,代码的可读性也会下降,相反concurrent提供的线程池却非常的便捷,不用自己操心死锁以及编写线程池代码,由于异步的概念IO型任务也更有优势。
既然如此,如果不是为了向下兼容2.x,是不是可以完全没有必要继续使用mutiprocessing和threading了?concurrent如此的优秀。
阿神2017-04-18 10:13:53
Concurrent sememangnya sangat berguna, terutamanya menyediakan ThreadPoolExecutor dan ProcessPoolExecutor. Berbilang benang, berbilang proses. Tetapi serentak pada asasnya adalah enkapsulasi threading dan mutiprocessing. Anda boleh mengetahui dengan melihat kod sumbernya.
ThreadPoolExecutor menyediakan baris gilir tugasnya sendiri, jadi tidak perlu menulisnya sendiri. Kumpulan utas yang dipanggil hanya membandingkan bilangan utas semasa dengan saiz max_workers yang ditentukan Jika saiznya lebih kecil daripada max_workers, tugasan dibenarkan untuk mencipta utas untuk melaksanakan tugas. Anda boleh melihat kod sumber
def _adjust_thread_count(self):
# When the executor gets lost, the weakref callback will wake up
# the worker threads.
def weakref_cb(_, q=self._work_queue):
q.put(None)
# TODO(bquinlan): Should avoid creating new threads if there are more
# idle threads than items in the work queue.
if len(self._threads) < self._max_workers:
t = threading.Thread(target=_worker,
args=(weakref.ref(self, weakref_cb),
self._work_queue))
t.daemon = True
t.start()
self._threads.add(t)
_threads_queues[t] = self._work_queue
Jadi, jika anda mengekalkan baris gilir sendiri, ia tidak menjadi masalah Cocurrent juga mengekalkan baris gilir secara dalaman, dan ia hanya ditulis untuk anda.
Bagi masalah kebuntuan, serentak juga boleh menyebabkan masalah kebuntuan. Biar saya berikan anda satu contoh, jalankan dan lihat
import time
from concurrent.futures import ThreadPoolExecutor
def wait_on_b():
time.sleep(5)
print(b.result()) # b will never complete because it is waiting on a.
return 5
def wait_on_a():
time.sleep(5)
print(a.result()) # a will never complete because it is waiting on b.
return 6
executor = ThreadPoolExecutor(max_workers=2)
a = executor.submit(wait_on_b)
b = executor.submit(wait_on_a)
ProcessPoolExecutor juga menggunakan mutiprocessing secara dalaman. Ia boleh menggunakan sepenuhnya ciri-ciri berbilang teras dan menyingkirkan sekatan GIL. Ambil perhatian bahawa apabila mentakrifkan ProcessPoolExecutor(max_workers=2), max_workers adalah lebih besar sedikit daripada bilangan teras CPU dan tidak boleh terlalu besar. ProcessPoolExecutor secara dalaman mengekalkan call_queue untuk mengekalkan baris gilir tugas, jenisnya ialah multiprocessing.Queue. Terdapat juga benang yang menguruskan baris gilir. Ini boleh dikatakan sebagai pengoptimuman cocurrent.
Anda boleh melihat kod sumber untuk butiran diri._adjust_process_count() sebenarnya memulakan proses untuk melaksanakan tugasan anda boleh mengetahuinya dengan mengklik pada _adjust_process_count. self._queue_management_thread ialah utas yang menguruskan baris gilir
if self._queue_management_thread is None:
# Start the processes so that their sentinels are known.
self._adjust_process_count()
self._queue_management_thread = threading.Thread(
target=_queue_management_worker,
args=(weakref.ref(self, weakref_cb),
self._processes,
self._pending_work_items,
self._work_ids,
self._call_queue,
self._result_queue))
self._queue_management_thread.daemon = True
self._queue_management_thread.start()
_threads_queues[self._queue_management_thread] = self._result_queue
Jadi cocurrent mudah digunakan, iaitu, ia melakukan pemprosesan yang lebih baik dengan sendirinya, seperti mengekalkan baris gilir dan mengurus baris gilir, jadi anda tidak perlu risau tentangnya. Sudah tentu anda juga boleh melaksanakannya sendiri. Anda boleh mencapai ini menggunakan cocurrent. Ia boleh dicapai dengan pemprosesan benang dan mutiproses Paling teruk, anda perlu melakukan kerja tambahan sendiri. Kerana cocurrent pada asasnya menggunakan dua teras ini. Sudah tentu, adalah lebih baik jika anda mempunyai cocurrent yang lebih baik yang sudah tersedia Anda boleh menggunakannya secara langsung dan bukannya mencipta semula roda itu sendiri. Jadi yang mana satu untuk digunakan bergantung pada kebiasaan peribadi anda Sebagai contoh, saya menggunakan python2, tetapi saya tidak boleh menggunakan cocurrent. Terpaksa guna threading.
阿神2017-04-18 10:13:53
Orang di atas telah mengatakannya dengan sangat jelas, saya cuma ingin menambah sedikit.
Concurrent.future menggunakan konsep tak segerak untuk menguruskan benang/proses, tetapi ia sebenarnya tidak merangkum IO tak segerak, jadi penanya berkata Peningkatan kecekapan IO sebenarnya salah.