이 기사에서는 미래를 통해 동시성 문제를 처리하기 위해 Python을 주로 소개합니다. 매우 훌륭하고 참조 가치가 있습니다. 필요한 친구는 참조할 수 있습니다.
미래에 대한 첫 소개
다음 스크립트를 사용하세요. 미래에 대한 예비 이해 :
예제 1: 일반 루프 방법
import os import time import sys import requests POP20_CC = ( "CN IN US ID BR PK NG BD RU JP MX PH VN ET EG DE IR TR CD FR" ).split() BASE_URL = 'http://flupy.org/data/flags' DEST_DIR = 'downloads/' def save_flag(img,filename): path = os.path.join(DEST_DIR,filename) with open(path,'wb') as fp: fp.write(img) def get_flag(cc): url = "{}/{cc}/{cc}.gif".format(BASE_URL,cc=cc.lower()) resp = requests.get(url) return resp.content def show(text): print(text,end=" ") sys.stdout.flush() def download_many(cc_list): for cc in sorted(cc_list): image = get_flag(cc) show(cc) save_flag(image,cc.lower()+".gif") return len(cc_list) def main(download_many): t0 = time.time() count = download_many(POP20_CC) elapsed = time.time()-t0 msg = "\n{} flags downloaded in {:.2f}s" print(msg.format(count,elapsed)) if __name__ == '__main__': main(download_many)
예 2: 미래 방법을 통해 구현, 여기서는 위 코드의 일부를 재사용합니다
from concurrent import futures from flags import save_flag, get_flag, show, main MAX_WORKERS = 20 def download_one(cc): image = get_flag(cc) show(cc) save_flag(image, cc.lower()+".gif") return cc def download_many(cc_list): workers = min(MAX_WORKERS,len(cc_list)) with futures.ThreadPoolExecutor(workers) as executor: res = executor.map(download_one, sorted(cc_list)) return len(list(res)) if __name__ == '__main__': main(download_many)
각각 세 번 실행합니다. 두 방법의 평균 속도 : 13.67과 1.59초에서는 여전히 그 차이가 매우 크다는 것을 알 수 있습니다.
future
future는 Concurrent.futures 모듈과 asyncio 모듈의 중요한 구성 요소입니다.
python3.4부터 표준 라이브러리에는 Future라는 두 개의 클래스가 있습니다: Concurrent.futures.Future 및 asyncio.Future
이 두 클래스는 동일한 목적을 수행합니다. 두 Future 클래스의 인스턴스는 완료되거나 완료되지 않을 수 있는 지연된 계산을 나타냅니다. Twisted의 Deferred 클래스 및 Tornado 프레임워크의 Future 클래스와 유사합니다
참고: 일반적으로 future를 직접 생성해서는 안 되며 동시 프레임워크(concurrent.futures 또는 asyncio)에 의해 인스턴스화됩니다
이유: future는 끝을 나타냅니다. 어떤 일이 일어날지 결정하는 유일한 방법은 실행 시간이 예약되어 있으므로 Concurrent.futures.Future 인스턴스는 무언가가 Concurrent.futures.Executor 하위 클래스로 넘겨질 때만 생성됩니다.
예: Executor.submit() 메소드의 매개변수는 호출 가능 객체입니다. 이 메소드를 호출하면 수신 호출 가능 객체에 대한 시간이 예약되며
future
클라이언트 코드는 미래 상태를 변경할 수 없습니다. 동시성 프레임워크는 미래로 표현되는 지연된 계산이 끝난 후 미래 개체의 상태를 변경하며 계산이 끝나는 시점을 제어할 수 없습니다.
두 future에는 .done() 메서드가 있습니다. 이 메서드는 차단되지 않으며 반환 값은 future에 연결된 호출 가능 객체가 실행되었는지 여부를 나타내는 부울 값입니다. 클라이언트 코드는 일반적으로 future 실행이 완료되었는지 묻지 않지만 알림을 기다립니다. 따라서 두 Future 클래스에는 모두 .add_done_callback() 메서드가 있습니다. 이 메서드에는 매개 변수가 하나만 있으며 유형은 호출 가능 객체입니다. 지정된 호출 가능 객체는 future가 실행된 후에 호출됩니다.
.result() 메서드는 두 개의 Future 클래스에서 동일한 기능을 갖습니다. 즉, 호출 가능 객체의 결과를 반환하거나 호출 가능 객체를 실행할 때 발생한 예외를 다시 발생시킵니다. 그러나 future 실행이 종료되지 않으면 두 Future 클래스의 결과 메서드 동작이 매우 다릅니다.
concurrent.futures.Future 인스턴스의 경우 .result() 메서드를 호출하면 반환할 결과가 있을 때까지 호출자의 스레드가 차단됩니다. 이때 결과 메서드는 지정된 경우 선택적 시간 초과 매개변수를 받을 수 있습니다. future가 시간 내에 실행을 마치지 않으면 TimeoutError 예외가 발생합니다.
asyncio.Future.result 메서드는 시간 제한 설정을 지원하지 않습니다. 향후 결과를 얻으려면 구조의 수율을 사용하는 것이 가장 좋지만 Concurrent.futures.Future는 이를 수행할 수 없습니다.
asyncio 또는 Concurrent.futures인지 여부. .Future, 여러 함수는 future를 반환하고 다른 함수는 future를 사용합니다. 첫 번째 예에서 우리가 사용하는 Executor.map은 future를 사용합니다. 반환 값은 반복자의 __next__ 메서드가 각 future의 결과를 호출합니다. 따라서 우리가 얻는 것은 미래 자체가 아니라 각 미래의 결과입니다
future.as_completed 함수 사용과 관련하여 여기서는 두 개의 루프를 사용합니다. 하나는 미래를 생성하고 예약하는 데 사용되고 다른 하나는 사용됩니다. 결과
from concurrent import futures from flags import save_flag, get_flag, show, main MAX_WORKERS = 20 def download_one(cc): image = get_flag(cc) show(cc) save_flag(image, cc.lower()+".gif") return cc def download_many(cc_list): cc_list = cc_list[:5] with futures.ThreadPoolExecutor(max_workers=3) as executor: to_do = [] for cc in sorted(cc_list): future = executor.submit(download_one,cc) to_do.append(future) msg = "Secheduled for {}:{}" print(msg.format(cc,future)) results = [] for future in futures.as_completed(to_do): res = future.result() msg = "{}result:{!r}" print(msg.format(future,res)) results.append(res) return len(results) if __name__ == '__main__': main(download_many)
결과는 다음과 같습니다.
참고: Python 코드는 IO 작업을 차단하는 표준 라이브러리의 모든 함수가 운영 체제를 기다리는 동안 GIL을 해제합니다. 결과를 반환하기 위해 다른 스레드를 실행하고, 이것이 바로 Python 스레드가 IO 집약적인 응용 프로그램에서 역할을 할 수 있는 이유입니다
위는 스레드를 시작하는 동시.futures이고, 다음은 프로세스를 시작하는 것입니다. 그것을 통해
concurrent.futures를 사용하여 프로세스를 시작
concurrent.futures ProcessPoolExecutor 클래스는 작업을 여러 Python 프로세스에 분산하므로 CPU 집약적인 처리가 필요한 경우 이 모듈을 사용하여 GIL을 우회하고 활용하십시오. 모든 CPU 코어.
원칙은 ProcessPoolExecutor가 N개의 독립적인 Python 인터프리터를 생성한다는 것입니다. 여기서 N은 시스템에서 사용 가능한 CPU 코어 수입니다.
사용 방법은 ThreadPoolExecutor 방법과 동일합니다
위 내용은 Python이 future를 통해 동시성 문제를 처리하는 방법에 대한 자세한 예의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!