>  기사  >  백엔드 개발  >  Python의 스레드 이해

Python의 스레드 이해

巴扎黑
巴扎黑원래의
2017-04-30 14:38:281234검색

Python에서 스레드를 사용하는 몇 가지 예와 스레드 경쟁을 피하는 방법을 살펴보겠습니다.

스레드가 예측 불가능하고 스레드가 실행될 때마다 다른 결과를 생성한다는 것을 알 수 있도록 다음 예제를 여러 번 실행해야 합니다. 면책조항: 지금부터 GIL에 대해 들어본 내용은 잊어버리세요. GIL은 제가 보여주려는 내용에 아무런 영향을 미치지 않기 때문입니다.

예시 1

우리는 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이 먼저 요청된 다음 반환된 결과가 인쇄되기 때문입니다.

예시 2

프로그램을 사용하여 여러 스레드 간의 리소스 경쟁을 시연하고 이 문제를 해결하겠습니다.

아아아아

이 프로그램을 여러 번 실행하면 다양한 결과를 볼 수 있습니다.

설명:

  • 모든 스레드가 수정하려는 전역 변수가 있습니다.


  • 모든 스레드는 이 전역 변수에 1을 추가해야 합니다.


  • 스레드가 50개이면 최종 값은 50이 되어야 하는데 그렇지 않습니다.

왜 50에 도달하지 않았습니까?

  • some_var15일 때 t1 스레드는 some_var을 읽고, 이 순간 CPU는 다른 스레드 t2에 제어권을 넘겨줍니다.


  • t2스레드가 읽은 some_var15


  • 입니다. t1t2 모두 some_var16


  • 을 추가합니다. 당시 우리가 기대했던 것은 t1 t2 두 개의 스레드가 some_var + 217


  • 여기에는 자원 경쟁이 있습니다.


  • 다른 스레드에서도 동일한 상황이 발생할 수 있으므로 최종 결과는

    미만일 수 있습니다. 50

자원경쟁 해결

아아아아

이 프로그램을 다시 실행하면 예상했던 결과를 얻을 수 있습니다.

설명:

  • 경쟁 조건을 방지하기 위해 잠금이 사용됩니다


  • 스레드가 일부 작업을 수행하기 전에 잠금을 획득한 경우. 다른 스레드는 t1이 잠금을 해제하기 전에 t1


  • 동일한 작업을 수행하지 않습니다.

  • 我们想要确定的是一旦线程t1已经读取了some_var,直到t1完成了修改some_var,其他的线程才可以读取some_var


  • 这样读取和修改some_var成了逻辑上的原子操作。

  实例3

  让我们用一个例子来证明一个线程不能影响其他线程内的变量(非全局变量)。

  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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.