Python3.2中引入的concurrent非常的好用,只用几行代码就可以编写出线程池/进程池,并且计算型任务效率和mutiprocessing.pool提供的poll和ThreadPoll相比不分伯仲,而且在IO型任务由于引入了Future的概念效率要高数倍。
而threading的话还要自己维护相关的队列防止死锁,代码的可读性也会下降,相反concurrent提供的线程池却非常的便捷,不用自己操心死锁以及编写线程池代码,由于异步的概念IO型任务也更有优势。
既然如此,如果不是为了向下兼容2.x,是不是可以完全没有必要继续使用mutiprocessing和threading了?concurrent如此的优秀。
Concurrent est en effet très utile, fournissant principalement ThreadPoolExecutor et ProcessPoolExecutor. Un multi-thread, un multi-processus. Mais concurrent est essentiellement une encapsulation de threads et de multitraitements. Vous pouvez le découvrir en consultant son code source.
ThreadPoolExecutor fournit sa propre file d'attente de tâches, il n'est donc pas nécessaire de l'écrire vous-même. Le soi-disant pool de threads compare simplement le nombre actuel de threads avec la taille définie de max_workers. Si la taille est inférieure à max_workers, la tâche est autorisée à créer des threads pour exécuter la tâche. Vous pouvez consulter le code source
def _adjust_thread_count(self):
Donc, si vous gérez la file d'attente vous-même, ce n'est pas un problème. Cocurrent gère également une file d'attente en interne, et elle est juste écrite pour vous.
En ce qui concerne le problème de blocage, la concurrence peut également provoquer des problèmes de blocage. Laissez-moi vous donner un exemple, exécutez-le et voyez
ProcessPoolExecutor utilise également le multitraitement en interne. Il peut exploiter pleinement les caractéristiques du multicœur et se débarrasser des restrictions du GIL. Notez que lors de la définition de ProcessPoolExecutor(max_workers=2), max_workers est légèrement supérieur au nombre de cœurs de processeur et ne peut pas être trop grand. ProcessPoolExecutor maintient en interne une call_queue pour maintenir la file d'attente des tâches, son type est multiprocessing.Queue. Il existe également un thread qui gère la file d'attente. Cela peut être considéré comme une optimisation du cocourant.
Vous pouvez voir le code source pour plus de détails. self._adjust_process_count() démarre réellement le processus pour exécuter la tâche. Vous pouvez le connaître en cliquant sur _adjust_process_count. self._queue_management_thread est le thread qui gère la file d'attente
Le cocourant est donc facile à utiliser, c'est-à-dire qu'il effectue lui-même un meilleur traitement, comme la maintenance des files d'attente et la gestion des threads de file d'attente, vous n'avez donc plus à vous en soucier. Bien entendu, vous pouvez également le mettre en œuvre vous-même. Vous pouvez y parvenir avec la simultanéité. Cela peut être réalisé avec le threading et le multitraitement, vous devez tout au plus effectuer un travail supplémentaire vous-même. Parce que le courant simultané utilise essentiellement ces deux noyaux. Bien sûr, il serait préférable que vous disposiez d’une meilleure cocourant déjà disponible. Vous pouvez l’utiliser directement au lieu de réinventer la roue vous-même. Donc, celui à utiliser dépend de votre familiarité personnelle. Par exemple, j'utilise python2, mais je ne peux pas utiliser le cocurrent. J'ai dû utiliser le threading.
La personne ci-dessus l'a déjà dit très clairement, je veux juste ajouter un petit peu.
Concurrent.future utilise le concept d'asynchrone pour gérer les threads/processus, mais il n'encapsule pas réellement les E/S asynchrones, donc le l'interrogateur a dit que l'amélioration de l'efficacité des IO est en fait fausse.
Concurrent est une coroutine, pas un fil, deux concepts.