Python에서 스레드를 사용하는 몇 가지 예와 스레드 경쟁을 피하는 방법을 살펴보겠습니다.
스레드가 예측 불가능하고 스레드가 실행될 때마다 다른 결과를 생성한다는 것을 알 수 있도록 다음 예제를 여러 번 실행해야 합니다. 면책조항: 지금부터 GIL에 대해 들어본 내용은 잊어버리세요. GIL은 제가 보여주려는 내용에 아무런 영향을 미치지 않기 때문입니다.
우리는 5개의 다른 URL을 요청할 예정입니다:
단일 스레드
아아아아출력은 다음과 같습니다:
import time import urllib2 def get_responses(): urls = [ 'http://www.google.com', 'http://www.amazon.com', 'http://www.ebay.com', 'http://www.alibaba.com', 'http://www.reddit.com' ] start = time.time() for url in urls: print url resp = urllib2.urlopen(url) print resp.getcode() print "Elapsed time: %s" % (time.time()-start) get_responses()
설명:
URL순서를 요청합니다
CPU가 하나의 URL에서 응답을 받지 않으면 다음 URL을 요청하지 않습니다
네트워크 요청은 시간이 오래 걸리므로 네트워크 요청의 반환을 기다리는 동안 CPU는 유휴 상태를 유지합니다.
멀티스레딩
아아아아출력:
http://www.google.com 200 http://www.amazon.com 200 http://www.ebay.com 200 http://www.alibaba.com 200 http://www.reddit.com 200 Elapsed time: 3.0814409256
설명:
프로그램 실행 시간 개선
우리는 CPU의 대기 시간을 줄이기 위해 다중 스레드 프로그램을 작성했습니다. 한 스레드에서 네트워크 요청이 반환될 때까지 CPU는 다른 스레드로 전환하여 다른 스레드에서 네트워크 요청을 할 수 있습니다.
스레드가 URL을 처리할 것으로 예상하므로 스레드 클래스를 인스턴스화할 때 URL을 전달합니다.
스레드 실행은 클래스에서 run()
메서드를 실행하는 것을 의미합니다.
그러나 우리는 각 스레드가 run()
을 실행하기를 원합니다.
각 URL에 대한 스레드를 생성하고 CPU에 스레드에서 start()
메서드를 실행하도록 지시하는 run()
메서드를 호출합니다.
모든 스레드의 실행이 완료되었을 때 소요된 시간을 계산하고 싶기 때문에 join()
메서드를 호출합니다.
join()
다음 명령을 실행하기 전에 이 스레드가 끝날 때까지 기다리도록 메인 스레드에 알릴 수 있습니다.
각 스레드에 대해 join()
메서드를 호출하므로 모든 스레드의 실행이 완료된 후 실행 시간을 계산합니다.
스레드 정보:
CPU는 start()
호출 직후 run()
메서드를 실행하지 않을 수 있습니다.
서로 다른 스레드 간에는 run()
의 실행 순서를 결정할 수 없습니다.
단일 스레드의 경우 run()
메서드의 문이 순서대로 실행된다는 것이 보장됩니다.
이는 스레드 내의 URL이 먼저 요청된 다음 반환된 결과가 인쇄되기 때문입니다.
프로그램을 사용하여 여러 스레드 간의 리소스 경쟁을 시연하고 이 문제를 해결하겠습니다.
아아아아이 프로그램을 여러 번 실행하면 다양한 결과를 볼 수 있습니다.
설명:
모든 스레드가 수정하려는 전역 변수가 있습니다.
모든 스레드는 이 전역 변수에 1을 추가해야 합니다.
스레드가 50개이면 최종 값은 50이 되어야 하는데 그렇지 않습니다.
왜 50에 도달하지 않았습니까?
some_var
이 15
일 때 t1
스레드는 some_var
을 읽고, 이 순간 CPU는 다른 스레드 t2
에 제어권을 넘겨줍니다.
t2
스레드가 읽은 some_var
도 15
입니다.
t1
및 t2
모두 some_var
16
을 추가합니다.
당시 우리가 기대했던 것은 t1
t2
두 개의 스레드가 some_var + 2
을 17
미만일 수 있습니다. 50
아아아아
이 프로그램을 다시 실행하면 예상했던 결과를 얻을 수 있습니다. 설명: 스레드가 일부 작업을 수행하기 전에 잠금을 획득한 경우. 다른 스레드는 t1
이 잠금을 해제하기 전에 t1
동일한 작업을 수행하지 않습니다.
我们想要确定的是一旦线程t1
已经读取了some_var
,直到t1
完成了修改some_var
,其他的线程才可以读取some_var
这样读取和修改some_var
成了逻辑上的原子操作。
让我们用一个例子来证明一个线程不能影响其他线程内的变量(非全局变量)。
time.sleep()可以使一个线程挂起,强制线程切换发生。
from threading import Thread import time class CreateListThread(Thread): def run(self): self.entries = [] for i in range(10): time.sleep(1) self.entries.append(i) print self.entries def use_create_list_thread(): for i in range(3): t = CreateListThread() t.start() use_create_list_thread()
运行几次后发现并没有打印出争取的结果。当一个线程正在打印的时候,cpu切换到了另一个线程,所以产生了不正确的结果。我们需要确保print self.entries
是个逻辑上的原子操作,以防打印时被其他线程打断。
我们使用了Lock(),来看下边的例子。
from threading import Thread, Lock import time lock = Lock() class CreateListThread(Thread): def run(self): self.entries = [] for i in range(10): time.sleep(1) self.entries.append(i) lock.acquire() print self.entries lock.release() def use_create_list_thread(): for i in range(3): t = CreateListThread() t.start() use_create_list_thread()
这次我们看到了正确的结果。证明了一个线程不可以修改其他线程内部的变量(非全局变量)。
原文出处: Akshar Raaj
위 내용은 Python의 스레드 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!