프로세스와 스레드는 운영체제의 기본 개념이지만 상대적으로 추상적이고 익히기가 어렵습니다. 멀티프로세스와 멀티스레딩에 관해 교과서에서 가장 고전적인 문장은 "프로세스는 자원할당의 최소 단위이고, 스레드는 CPU 스케줄링의 최소 단위이다"이다. 스레드는 프로그램의 단일 순차적 제어 흐름입니다. 프로세스 내에서 상대적으로 독립적이고 스케줄링 가능한 실행 단위입니다. 시스템이 독립적으로 CPU를 스케줄링하고 할당하는 기본 단위입니다. 단일 프로그램에서 여러 작업을 완료하기 위해 동시에 여러 스레드를 실행하는 것을 멀티스레딩이라고 합니다.
프로세스는 자원 할당의 기본 단위입니다. 공정과 관련된 모든 자원은 공정 제어 블록 PCB에 기록됩니다. 프로세스가 이러한 리소스를 소유하거나 사용하고 있음을 나타냅니다. 또한 프로세스는 프로세서를 선점하는 스케줄링 단위이기도 하며 완전한 가상 주소 공간을 갖습니다. 프로세스가 예약되면 서로 다른 프로세스는 서로 다른 가상 주소 공간을 가지며 동일한 프로세스 내의 서로 다른 스레드는 동일한 주소 공간을 공유합니다.
프로세스에 해당하는 스레드는 리소스 할당과 관련이 없으며 특정 프로세스에 속하며 프로세스의 다른 스레드와 프로세스의 리소스를 공유합니다. 스레드는 관련 스택(시스템 스택 또는 사용자 스택) 레지스터와 스레드 제어 테이블 TCB로만 구성됩니다. 레지스터는 스레드 내에 지역 변수를 저장하는 데 사용할 수 있지만 다른 스레드와 관련된 변수는 저장할 수 없습니다.
일반적으로 프로세스에는 프로세스가 소유한 리소스를 활용할 수 있는 여러 스레드가 포함될 수 있습니다. 스레드를 도입한 운영 체제에서 프로세스는 일반적으로 자원 할당의 기본 단위로 간주되며, 스레드는 독립적인 작업 및 독립적인 스케줄링의 기본 단위로 간주됩니다.
스레드는 프로세스보다 작고 기본적으로 시스템 리소스를 소유하지 않기 때문에 스레드를 예약하는 데 드는 오버헤드가 훨씬 작아지고 시스템의 여러 프로그램 간의 동시 실행 정도를 보다 효율적으로 높일 수 있으므로 시스템 리소스 활용도와 시스템 리소스 활용도가 크게 향상됩니다. 처리량.
따라서 최근 출시된 범용 운영 체제에서는 시스템의 동시성을 더욱 향상시키기 위해 스레드를 도입했으며 이를 현대 운영 체제의 중요한 지표로 간주합니다.
스레드와 프로세스의 차이점은 다음 네 가지로 요약할 수 있습니다.
크기 비교 |
멀티 프로세스 | 멀티스레딩 |
요약 |
데이터 공유 및 동기화 |
데이터 공유는 복잡하고 동기화는 간단합니다 |
데이터 공유는 간단하고 동기화는 복잡합니다 |
각각의 장점과 단점이 있습니다 |
메모리, CPU |
를 차지합니다. 많은 메모리, 복잡한 전환, CPU 사용률 낮음 |
더 적은 메모리 차지, 간단한 전환, 높은 CPU 사용률 |
스레드가 지배적 |
생성, 파괴, 전환 |
복잡함, 느림 | 간단하고 빠르다 |
스레드가 지배적 |
프로그래밍 및 디버깅 |
간단한 프로그래밍 및 간단한 디버깅 |
복잡한 프로그래밍 및 복잡한 디버깅 |
프로세스가 지배합니다 |
신뢰성 |
프로세스가 서로 영향을 미치지 않습니다 |
스레드 하나가 멈추면 전체 프로세스가 중단됩니다 |
프로세스 지배력 |
분산 |
멀티 코어 및 멀티 머신에 적합하며 여러 머신으로 확장이 용이함 | 적합한 지배적 멀티 코어 |
프로세스 |
요약하자면, 프로세스와 스레드는 기차와 마차에 비유될 수도 있습니다.
Global Interpreter Lock(영어: Global Interpreter Lock, 약어 GIL)은 아님 Python의 기능으로 구현됩니다. Python 파서(CPython)에서 도입한 개념입니다. CPython은 대부분의 환경에서 기본 Python 실행 환경이기 때문입니다. 따라서 많은 사람들의 개념에서는 CPython이 Python이고 GIL이 Python 언어의 결함이라고 당연하게 여깁니다. 그렇다면 CPython 구현에서 GIL은 무엇입니까? 공식 설명을 살펴보겠습니다.
한 번에 하나의 스레드만 Python 바이트코드를 실행하도록 보장하기 위해 CPython 인터프리터에서 사용하는 메커니즘입니다. 이는 객체 모델(예: 중요한 내장 유형 포함)을 만들어 CPython 구현을 단순화합니다. dict) 전체 인터프리터를 잠그면 멀티 프로세서 시스템에서 제공하는 병렬 처리가 많이 희생되면서 인터프리터가 멀티 스레드를 더 쉽게 수행할 수 있습니다.
Python 코드 실행은 Python 가상 코드에 의해 수행됩니다. 머신(인터프리터 메인 루프, CPython 버전이라고도 함)을 제어하기 위해 Python은 원래 인터프리터의 메인 루프에서 동시에 하나의 스레드만 실행되도록 설계되었습니다. 즉, 언제든지 하나의 스레드만 인터프리터에서 실행됩니다. Python 가상 머신에 대한 액세스는 한 번에 하나의 스레드만 실행되도록 보장하는 GIL(Global Interpreter Lock)에 의해 제어됩니다.
GIL의 장점은 무엇인가요? 간단히 말해서 단일 스레드 상황에서는 더 빠르고 C 라이브러리와 결합하면 더 편리하며 스레드 안전성 문제를 고려할 필요도 없습니다. 이는 초기 Python의 가장 일반적인 응용 시나리오이자 장점이기도 했습니다. 또한 GIL의 설계는 CPython의 구현을 단순화하여 사전과 같은 주요 내장 유형을 포함한 객체 모델을 암시적으로 동시에 액세스할 수 있게 만듭니다. 전역 인터프리터를 잠그면 멀티스레딩 지원을 구현하기가 더 쉬워지지만 멀티프로세서 호스트의 병렬 컴퓨팅 기능도 상실됩니다.
멀티 스레드 환경에서 Python 가상 머신은 다음과 같이 실행됩니다.
Python3.2 이전에는 GIL의 릴리스 로직이 현재 스레드였습니다. IO 작업이 발생했거나 틱 수가 100에 도달하고(틱은 특별히 GIL에 사용되는 Python 자체의 카운터로 간주될 수 있으며 각 릴리스 후에 0으로 재설정됩니다. 이 수는 sys.setcheckinterval을 통해 조정할 수 있음) 릴리스됩니다. 컴퓨팅 집약적인 스레드는 GIL을 해제한 후 즉시 GIL을 신청하고 일반적으로 다른 스레드가 예약을 완료하기 전에 GIL을 다시 획득하기 때문에 컴퓨팅 집약적인 스레드는 매우 짧은 시간에 GIL을 획득하게 됩니다. GIL은 스레드 실행이 끝날 때까지 오랜 시간 동안 점유됩니다.
Python 3.2는 새로운 GIL을 사용하기 시작합니다. 새로운 GIL 구현에서는 고정된 시간 초과를 사용하여 현재 스레드에 전역 잠금을 포기하도록 지시합니다. 현재 스레드가 이 잠금을 보유하고 있고 다른 스레드가 이 잠금을 요청하면 현재 스레드는 5밀리초 후에 강제로 잠금을 해제하게 됩니다. 이번 개선으로 단일 코어의 경우 단일 스레드가 오랫동안 GIL을 점유하는 상황이 개선됐다.
단일 코어 CPU에서는 수백 번의 간격 검사로 인해 스레드 전환이 발생합니다. 멀티 코어 CPU에서는 심각한 스레드 스래싱이 발생합니다. GIL 잠금이 해제될 때마다 스레드는 잠금을 놓고 경쟁하고 스레드를 전환하여 리소스를 소비합니다. 단일 코어 아래에 여러 스레드가 있으면 GIL이 해제될 때마다 깨어난 스레드가 GIL 잠금을 얻을 수 있으므로 원활하게 실행할 수 있습니다. 그러나 멀티 코어에서는 CPU0이 GIL을 해제한 후 다른 CPU의 스레드가 경쟁합니다. 그러나 GIL은 CPU0에 의해 즉시 획득될 수 있으며, 이로 인해 다른 여러 CPU의 깨어난 스레드가 깨어나 예약 상태로 들어가기 전에 전환 시간을 기다리게 됩니다. 이로 인해 스레드 스래싱이 발생하여 효율성이 저하됩니다.
또한, 위의 구현 메커니즘에서 Python의 멀티스레딩이 CPU 집약적인 코드보다 IO 집약적인 코드에 더 친숙하다는 것을 추론할 수 있습니다.
GIL에 대한 대책:
Python의 스레딩 패키지는 주로 멀티스레딩 개발을 사용하지만 GIL의 존재로 인해 Python의 멀티스레딩은 실제로 멀티스레딩이 아닙니다. 멀티 코어 CPU의 리소스를 최대한 활용하려면 대부분의 경우 여러 프로세스를 사용해야 합니다. 멀티프로세싱 패키지는 Python 2.6에서 도입되었습니다. 이 패키지는 마이그레이션을 용이하게 하기 위해 스레딩에서 제공하는 인터페이스 세트를 완전히 복제합니다. 유일한 차이점은 다중 스레드 대신 다중 프로세스를 사용한다는 것입니다. 각 프로세스에는 독립적인 GIL이 있으므로 프로세스 간에 GIL 경합이 발생하지 않습니다.
이 다중 처리를 사용하면 단일 프로세스에서 동시 실행으로의 변환을 쉽게 완료할 수 있습니다. 멀티프로세싱은 하위 프로세스, 통신 및 데이터 공유를 지원하고 다양한 형태의 동기화를 수행하며 프로세스, 큐, 파이프 및 잠금과 같은 구성 요소를 제공합니다.
파이썬의 GIL을 처리하는 것 외에도 멀티프로세싱을 하는 또 다른 이유는 Windows 운영 체제와 Linux/Unix 시스템 간의 불일치 때문입니다.
Unix/Linux 운영 체제는 매우 특별한 fork() 시스템 호출을 제공합니다. 일반적인 함수는 한 번 호출하고 한 번 반환하지만, fork()는 한 번 호출하고 두 번 반환하는데, 운영체제가 현재 프로세스(부모 프로세스)(자식 프로세스)를 자동으로 복사한 후 각각 부모 프로세스와 자식 프로세스에 복사하기 때문이다. . 반품. 자식 프로세스는 항상 0을 반환하고, 부모 프로세스는 자식 프로세스의 ID를 반환합니다. 그 이유는 부모 프로세스가 많은 자식 프로세스를 분기할 수 있으므로 부모 프로세스는 각 자식 프로세스의 ID를 기록해야 하고 자식 프로세스는 부모 프로세스의 ID를 가져오기 위해 getpid()만 호출하면 되기 때문입니다.
Python의 os 모듈은 Python 프로그램에서 하위 프로세스를 쉽게 생성할 수 있는 fork를 포함한 일반적인 시스템 호출을 캡슐화합니다.
import os print('Process (%s) start...' % os.getpid()) # Only works on Unix/Linux/Mac: pid = os.fork() if pid == 0: print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())) else: print('I (%s) just created a child process (%s).' % (os.getpid(), pid))
Linux, Unix 및 Mac에서 위 코드의 실행 결과는 다음과 같습니다.
Process (876) start... I (876) just created a child process (877). I am child process (877) and my parent is 876.
Fork 호출을 사용하는 경우 프로세스가 새 작업을 받으면 새 작업을 처리하기 위해 하위 프로세스를 복사할 수 있습니다. 일반적인 Apache 서버에는 새 http 요청이 있을 때마다 이를 처리하기 위해 하위 프로세스가 분기됩니다. http 요청.
Windows에는 포크 호출이 없으므로 위 코드는 Windows에서 실행될 수 없습니다. Python은 크로스 플랫폼이므로 자연스럽게 크로스 플랫폼 다중 프로세스 지원을 제공해야 합니다. 다중 처리 모듈은 다중 프로세스 모듈의 크로스 플랫폼 버전입니다. 다중 처리 모듈은 fork() 호출을 캡슐화하므로 우리는 fork()의 세부 사항에 주의를 기울일 필요가 없습니다. Windows에는 포크 호출이 없으므로 다중 처리에서는 포크 효과를 "시뮬레이트"해야 합니다.
관리 프로세스 모듈 생성:
동기화 하위 프로세스 모듈:
Connect 각 구성요소와 기능을 함께 사용하는 방법을 알아봅시다.
Multiprocessing 모듈은 프로세스 객체를 나타내는 Process 클래스를 제공합니다.
Multiprocessing에서 각 프로세스는 Process 클래스로 표현됩니다.
구성 방법: Process([group [, target. [, 이름 [, args [, kwargs]]]]))
实例方法:
属性介绍:
使用示例:(注意:在windows中Process()必须放到if name == ‘main’:下)
from multiprocessing import Process import os def run_proc(name): print('Run child process %s (%s)...' % (name, os.getpid())) if __name__=='__main__': print('Parent process %s.' % os.getpid()) p = Process(target=run_proc, args=('test',)) print('Child process will start.') p.start() p.join() print('Child process end.')
Pool类用于需要执行的目标很多,而手动限制进程数量又太繁琐时,如果目标少且不用控制进程数量则可以用Process类。Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,就重用进程池中的进程。
构造方法:Pool([processes[, initializer[, initargs[, maxtasksperchild[, context]]]]])
实例方法:
方法apply_async()和map_async()的返回值是AsyncResul的实例obj。实例具有以下方法:
<span style="color: rgb(106, 115, 125); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);"># -*- coding:utf-8 -*-</span><br><span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">Queue(用于进程通信,资源共享)</span><br><span style="color: rgb(106, 115, 125); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);"># Pool+map</span><br><span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">from</span> <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">multiprocessing</span> <span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">import</span> <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">Pool</span><br><span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">def</span> <span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">test</span>(<span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">i</span>):<br><span style="color: rgb(111, 66, 193); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">print</span>(<span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">i</span>)<br><span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">if</span> <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">__name__</span> <span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">==</span> <span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">"__main__"</span>:<br><span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">lists</span> <span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">=</span> <span style="color: rgb(111, 66, 193); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">range</span>(<span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">100</span>)<br><span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">pool</span> <span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">=</span> <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">Pool</span>(<span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">8</span>)<br><span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">pool</span>.<span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">map</span>(<span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">test</span>, <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">lists</span>)<br><span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">pool</span>.<span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">close</span>()<br><span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">pool</span>.<span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">join</span>()<br>
<span style="color: rgb(106, 115, 125); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);"># -*- coding:utf-8 -*-</span><br><span style="color: rgb(106, 115, 125); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);"># 异步进程池(非阻塞)</span><br><span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">from</span> <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">multiprocessing</span> <span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">import</span> <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">Pool</span><br><span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">def</span> <span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">test</span>(<span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">i</span>):<br><span style="color: rgb(111, 66, 193); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">print</span>(<span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">i</span>)<br><span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">if</span> <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">__name__</span> <span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">==</span> <span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">"__main__"</span>:<br><span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">pool</span> <span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">=</span> <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">Pool</span>(<span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">8</span>)<br><span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">for</span> <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">i</span> <span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">in</span> <span style="color: rgb(111, 66, 193); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">range</span>(<span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">100</span>):<br><span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">'''</span><br><span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">For循环中执行步骤:</span><br><span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">(1)循环遍历,将100个子进程添加到进程池(相对父进程会阻塞)</span><br><span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">(2)每次执行8个子进程,等一个子进程执行完后,立马启动新的子进程。(相对父进程不阻塞)</span><br><span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">apply_async为异步进程池写法。异步指的是启动子进程的过程,与父进程本身的执行(print)是异步的,而For循环中往进程池添加子进程的过程,与父进程本身的执行却是同步的。</span><br><span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">'''</span><br><span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">pool</span>.<span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">apply_async</span>(<span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">test</span>, <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">args</span><span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">=</span>(<span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">i</span>,))<span style="color: rgb(106, 115, 125); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);"># 维持执行的进程总数为8,当一个进程执行完后启动一个新进程.</span><br><span style="color: rgb(111, 66, 193); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">print</span>(<span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">"test"</span>)<br><span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">pool</span>.<span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">close</span>()<br><span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">pool</span>.<span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">join</span>()<br>
<span style="color: rgb(106, 115, 125); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);"># -*- coding:utf-8 -*-</span><br><span style="color: rgb(106, 115, 125); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);"># 异步进程池(非阻塞)</span><br><span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">from</span> <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">multiprocessing</span> <span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">import</span> <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">Pool</span><br><span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">def</span> <span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">test</span>(<span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">i</span>):<br><span style="color: rgb(111, 66, 193); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">print</span>(<span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">i</span>)<br><span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">if</span> <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">__name__</span> <span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">==</span> <span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">"__main__"</span>:<br><span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">pool</span> <span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">=</span> <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">Pool</span>(<span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">8</span>)<br><span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">for</span> <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">i</span> <span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">in</span> <span style="color: rgb(111, 66, 193); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">range</span>(<span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">100</span>):<br><span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">'''</span><br><span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">实际测试发现,for循环内部执行步骤:</span><br><span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">(1)遍历100个可迭代对象,往进程池放一个子进程</span><br><span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">(2)执行这个子进程,等子进程执行完毕,再往进程池放一个子进程,再执行。(同时只执行一个子进程)</span><br><span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">for循环执行完毕,再执行print函数。</span><br><span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">'''</span><br><span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">pool</span>.<span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">apply</span>(<span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">test</span>, <span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">args</span><span style="color: rgb(215, 58, 73); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">=</span>(<span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">i</span>,))<span style="color: rgb(106, 115, 125); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);"># 维持执行的进程总数为8,当一个进程执行完后启动一个新进程.</span><br><span style="color: rgb(111, 66, 193); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">print</span>(<span style="color: rgb(102, 153, 0); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">"test"</span>)<br><span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">pool</span>.<span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">close</span>()<br><span style="color: rgb(89, 89, 89); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">pool</span>.<span style="color: rgb(0, 92, 197); margin: 0px; padding: 0px; background: none 0% 0% / auto repeat scroll padding-box border-box rgba(0, 0, 0, 0);">join</span>()<br>
在使用多进程的过程中,最好不要使用共享资源。普通的全局变量是不能被子进程所共享的,只有通过Multiprocessing组件构造的数据结构可以被共享。
Queue是用来创建进程间资源共享的队列的类,使用Queue可以达到多进程间数据传递的功能(缺点:只适用Process类,不能在Pool进程池中使用)。
构造方法:Queue([maxsize])
实例方法:
使用示例:
from multiprocessing import Process, Queue import os, time, random def write(q): print('Process to write: %s' % os.getpid()) for value in ['A', 'B', 'C']: print('Put %s to queue...' % value) q.put(value) time.sleep(random.random()) def read(q): print('Process to read: %s' % os.getpid()) while True: value = q.get(True) print('Get %s from queue.' % value) if __name__ == "__main__": q = Queue() pw = Process(target=write, args=(q,)) pr = Process(target=read, args=(q,)) pw.start() pr.start() pw.join()# 等待pw结束 pr.terminate()# pr进程里是死循环,无法等待其结束,只能强行终止
JoinableQueue就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。
构造方法:JoinableQueue([maxsize])
实例方法
JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
使用示例:
# -*- coding:utf-8 -*- from multiprocessing import Process, JoinableQueue import time, random def consumer(q): while True: res = q.get() print('消费者拿到了 %s' % res) q.task_done() def producer(seq, q): for item in seq: time.sleep(random.randrange(1,2)) q.put(item) print('生产者做好了 %s' % item) q.join() if __name__ == "__main__": q = JoinableQueue() seq = ('产品%s' % i for i in range(5)) p = Process(target=consumer, args=(q,)) p.daemon = True# 设置为守护进程,在主线程停止时p也停止,但是不用担心,producer内调用q.join保证了consumer已经处理完队列中的所有元素 p.start() producer(seq, q) print('主线程')
multiprocessing 中Value和Array的实现原理都是在共享内存中创建ctypes()对象来达到共享数据的目的,两者实现方法大同小异,只是选用不同的ctypes数据类型而已。
构造方法:Value((typecode_or_type, args[, lock])
typecode_or_type支持的类型:
| Type code | C Type | Python Type | Minimum size in bytes | | --------- | ------------------ | ----------------- | --------------------- | | `'b'` | signed char| int | 1 | | `'B'` | unsigned char| int | 1 | | `'u'` | Py_UNICODE | Unicode character | 2 | | `'h'` | signed short | int | 2 | | `'H'` | unsigned short | int | 2 | | `'i'` | signed int | int | 2 | | `'I'` | unsigned int | int | 2 | | `'l'` | signed long| int | 4 | | `'L'` | unsigned long| int | 4 | | `'q'` | signed long long | int | 8 | | `'Q'` | unsigned long long | int | 8 | | `'f'` | float| float | 4 | | `'d'` | double | float | 8 |
参考地址:https://docs.python.org/3/library/array.html
构造方法:Array(typecode_or_type, size_or_initializer, **kwds[, lock])
使用示例:
import multiprocessing def f(n, a): n.value = 3.14 a[0] = 5 if __name__ == '__main__': num = multiprocessing.Value('d', 0.0) arr = multiprocessing.Array('i', range(10)) p = multiprocessing.Process(target=f, args=(num, arr)) p.start() p.join() print(num.value) print(arr[:])
注意:Value和Array只适用于Process类。
多进程还有一种数据传递方式叫管道原理和 Queue相同。Pipe可以在进程之间创建一条管道,并返回元组(conn1,conn2),其中conn1,conn2表示管道两端的连接对象,强调一点:必须在产生Process对象之前产生管道。
构造方法:Pipe([duplex])
实例方法:
使用示例:
from multiprocessing import Process, Pipe import time # 子进程执行方法 def f(Subconn): time.sleep(1) Subconn.send("吃了吗") print("来自父亲的问候:", Subconn.recv()) Subconn.close() if __name__ == "__main__": parent_conn, child_conn = Pipe()# 创建管道两端 p = Process(target=f, args=(child_conn,))# 创建子进程 p.start() print("来自儿子的问候:", parent_conn.recv()) parent_conn.send("嗯")
Manager()返回的manager对象控制了一个server进程,此进程包含的python对象可以被其他的进程通过proxies来访问。从而达到多进程间数据通信且安全。Manager模块常与Pool模块一起使用。
Manager支持的类型有list,dict,Namespace,Lock,RLock,Semaphore,BoundedSemaphore,Condition,Event,Queue,Value和Array。
管理器是独立运行的子进程,其中存在真实的对象,并以服务器的形式运行,其他进程通过使用代理访问共享对象,这些代理作为客户端运行。Manager()是BaseManager的子类,返回一个启动的SyncManager()实例,可用于创建共享对象并返回访问这些共享对象的代理。
BaseManager,创建管理器服务器的基类
构造方法:BaseManager([address[, authkey]])
实例方法:
实例属性:
SyncManager,以下类型均不是进程安全的,需要加锁..
实例方法:
使用示例:
import multiprocessing def f(x, arr, l, d, n): x.value = 3.14 arr[0] = 5 l.append('Hello') d[1] = 2 n.a = 10 if __name__ == '__main__': server = multiprocessing.Manager() x = server.Value('d', 0.0) arr = server.Array('i', range(10)) l = server.list() # 子进程执行方法 def f(Subconn): time.sleep(1) Subconn.send("吃了吗") print("来自父亲的问候:", Subconn.recv()) print(x.value) print(arr) print(l) print(d) print(n)
Lock锁的作用是当多个进程需要访问共享资源的时候,避免访问的冲突。加锁保证了多个进程修改同一块数据时,同一时间只能有一个修改,即串行的修改,牺牲了速度但保证了数据安全。Lock包含两种状态——锁定和非锁定,以及两个基本的方法。
构造方法:Lock()
实例方法:
使用示例:
from multiprocessing import Process, Lock def l(lock, num): lock.acquire() print("Hello Num: %s" % (num)) lock.release() if __name__ == '__main__': lock = Lock()# 这个一定要定义为全局 for num in range(20): Process(target=l, args=(lock, num)).start()
RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数。可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。
构造方法:RLock()
实例方法:
信号量是一个更高级的锁机制。信号量内部有一个计数器而不像锁对象内部有锁标识,而且只有当占用信号量的线程数超过信号量时线程才阻塞。这允许了多个线程可以同时访问相同的代码区。比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去,如果指定信号量为3,那么来一个人获得一把锁,计数加1,当计数等于3时,后面的人均需要等待。一旦释放,就有人可以获得一把锁。
构造方法:Semaphore([value])
实例方法:
使用示例:
from multiprocessing import Process, Semaphore import time, random def go_wc(sem, user): sem.acquire() print('%s 占到一个茅坑' % user) time.sleep(random.randint(0, 3)) sem.release() print(user, 'OK') if __name__ == '__main__': sem = Semaphore(2) p_l = [] for i in range(5): p = Process(target=go_wc, args=(sem, 'user%s' % i,)) p.start() p_l.append(p) for i in p_l: i.join()
可以把Condition理解为一把高级的锁,它提供了比Lock, RLock更高级的功能,允许我们能够控制复杂的线程同步问题。Condition在内部维护一个锁对象(默认是RLock),可以在创建Condigtion对象的时候把琐对象作为参数传入。Condition也提供了acquire, release方法,其含义与锁的acquire, release方法一致,其实它只是简单的调用内部锁对象的对应的方法而已。Condition还提供了其他的一些方法。
构造方法:Condition([lock/rlock])
实例方法:
使用示例:
import multiprocessing import time def stage_1(cond): """perform first stage of work, then notify stage_2 to continue """ name = multiprocessing.current_process().name print('Starting', name) with cond: print('{} done and ready for stage 2'.format(name)) cond.notify_all() def stage_2(cond): """wait for the condition telling us stage_1 is done""" name = multiprocessing.current_process().name print('Starting', name) with cond: cond.wait() print('{} running'.format(name)) if __name__ == '__main__': condition = multiprocessing.Condition() s1 = multiprocessing.Process(name='s1', target=stage_1, args=(condition,)) s2_clients = [ multiprocessing.Process( name='stage_2[{}]'.format(i), target=stage_2, args=(condition,), ) for i in range(1, 3) ] for c in s2_clients: c.start() time.sleep(1) s1.start() s1.join() for c in s2_clients: c.join()
Event内部包含了一个标志位,初始的时候为false。可以使用set()来将其设置为true;或者使用clear()将其从新设置为false;可以使用is_set()来检查标志位的状态;另一个最重要的函数就是wait(timeout=None),用来阻塞当前线程,直到event的内部标志位被设置为true或者timeout超时。如果内部标志位为true则wait()函数理解返回。
使用示例:
import multiprocessing import time def wait_for_event(e): """Wait for the event to be set before doing anything""" print('wait_for_event: starting') e.wait() print('wait_for_event: e.is_set()->', e.is_set()) def wait_for_event_timeout(e, t): """Wait t seconds and then timeout""" print('wait_for_event_timeout: starting') e.wait(t) print('wait_for_event_timeout: e.is_set()->', e.is_set()) if __name__ == '__main__': e = multiprocessing.Event() w1 = multiprocessing.Process( name='block', target=wait_for_event, args=(e,), ) w1.start() w2 = multiprocessing.Process( name='nonblock', target=wait_for_event_timeout, args=(e, 2), ) w2.start() print('main: waiting before calling Event.set()') time.sleep(3) e.set() print('main: event is set')
multiprocessing.dummy 模块与 multiprocessing 模块的区别:dummy 模块是多线程,而 multiprocessing 是多进程, api 都是通用的。所有可以很方便将代码在多线程和多进程之间切换。multiprocessing.dummy通常在IO场景可以尝试使用,比如使用如下方式引入线程池。
from multiprocessing.dummy import Pool as ThreadPool
multiprocessing.dummy与早期的threading,不同的点好像是在多多核CPU下,只绑定了一个核心(具体未考证)。
参考文档:
Python标准库为我们提供了threading和multiprocessing模块编写相应的多线程/多进程代码。从Python3.2开始,标准库为我们提供了concurrent.futures模块,它提供了ThreadPoolExecutor和ProcessPoolExecutor两个类,实现了对threading和multiprocessing的更高级的抽象,对编写线程池/进程池提供了直接的支持。concurrent.futures基础模块是executor和future。
Executor是一个抽象类,它不能被直接使用。它为具体的异步执行定义了一些基本的方法。ThreadPoolExecutor和ProcessPoolExecutor继承了Executor,分别被用来创建线程池和进程池的代码。
ThreadPoolExecutor类是Executor子类,使用线程池执行异步调用。
class concurrent.futures.ThreadPoolExecutor(max_workers)
使用max_workers数目的线程池执行异步调用。
ThreadPoolExecutor类是Executor子类,使用进程池执行异步调用。
class concurrent.futures.ProcessPoolExecutor(max_workers=None)
使用max_workers数目的进程池执行异步调用,如果max_workers为None则使用机器的处理器数目(如4核机器max_worker配置为None时,则使用4个进程进行异步并发)。
Executor中定义了submit()方法,这个方法的作用是提交一个可执行的回调task,并返回一个future实例。future对象代表的就是给定的调用。
Executor.submit(fn, *args, **kwargs)
使用示例:
from concurrent import futures def test(num): import time return time.ctime(), num with futures.ThreadPoolExecutor(max_workers=1) as executor: future = executor.submit(test, 1) print(future.result())
除了submit,Exectuor还为我们提供了map方法,这个方法返回一个map(func, *iterables)迭代器,迭代器中的回调执行返回的结果有序的。
Executor.map(func, *iterables, timeout=None)
使用示例:
from concurrent import futures def test(num): import time return time.ctime(), num data = [1, 2, 3] with futures.ThreadPoolExecutor(max_workers=1) as executor: for future in executor.map(test, data): print(future)
释放系统资源,在Executor.submit()或 Executor.map()等异步操作后调用。使用with语句可以避免显式调用此方法。
Executor.shutdown(wait=True)
Future可以理解为一个在未来完成的操作,这是异步编程的基础。通常情况下,我们执行io操作,访问url时(如下)在等待结果返回之前会产生阻塞,cpu不能做其他事情,而Future的引入帮助我们在等待的这段时间可以完成其他的操作。
Future类封装了可调用的异步执行。Future 实例通过 Executor.submit()方法创建。
使用示例:
from concurrent.futures import ThreadPoolExecutor, wait, as_completed from time import sleep from random import randint def return_after_5_secs(num): sleep(randint(1, 5)) return "Return of {}".format(num) pool = ThreadPoolExecutor(5) futures = [] for x in range(5): futures.append(pool.submit(return_after_5_secs, x)) print(1) for x in as_completed(futures): print(x.result()) print(2)
参考链接:
위 내용은 Python 멀티스레딩 및 멀티프로세스 세부 정리의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!