2013-10-29 3 views
2

내 테스트 코드는 스레딩을 사용하여 다음과 같습니다. 카운트가 5,000,000이 아니므로 데이터 경쟁이 있었지만 gevent를 사용하면 카운트가 5,000,000이고 데이터가 없었습니다 경주.스레딩 데이터 경쟁이 발생하지만 gevent를 사용하지 않는 이유는 무엇입니까?

gevent coroutine 실행은 하나의 CPU 명령어로 분할하지 않고 "count + = 1"원자로 실행합니까?

# -*- coding: utf-8 -*- 
import threading 

use_gevent = True   
use_debug = False   
cycles_count = 100*10000 


if use_gevent: 
    from gevent import monkey 
    monkey.patch_thread() 

count = 0 


class Counter(threading.Thread): 
    def __init__(self, name): 
     self.thread_name = name 
     super(Counter, self).__init__(name=name) 

    def run(self): 
     global count 
     for i in xrange(cycles_count): 
      if use_debug: 
       print '%s:%s' % (self.thread_name, count) 
      count = count + 1 

counters = [Counter('thread:%s' % i) for i in range(5)] 
for counter in counters: 
    counter.start() 
for counter in counters: 
    counter.join() 

print 'count=%s' % count 
+0

안녕하세요. @onlytiancai, 질문의 중국어 버전을 삭제했습니다.이 사이트는 영어로 충분합니다. 감사! –

답변

3

화합물 할당 (+ =)은 파이썬에서는 원 자성이 아니며 gevent는이를 변경하지 않습니다.

gevent coroutines가 시스템 스레드가 아니고 gevent의 컨텍스트 스위치가 os에 의해 제어되지 않으며 스레드가 차단 될 때까지 gevent가 전환되지 않기 때문에 gevent 패치 된 스레드를 사용한 횟수는 항상 5,000,000입니다.

정상적인 스레드의 경우 사물이 다릅니다. 복합 할당은 3 단계 (a 값 읽기, b 값 증가, c 변경 값 지정)를 포함하고 있기 때문에 이러한 단계간에 스레드 전환이 발생할 수 있습니다.

아래 코드를 확인하여 무한 루프를 실행할 새 스레드를 추가합니다. 일반 스레드의 경우 os가 스레드를 자동으로 전환하므로 count를 인쇄 할 수 있습니다. 하지만 gevent 스레드의 경우 count가 인쇄되지 않습니다. 왜냐하면 무한 스레드가 실행되면 결코 종료되지 않으므로 gevent는 IO가 발생하지 않기 때문에 다른 스레드로 전환하지 않기 때문입니다.

# -*- coding: utf-8 -*- 
import threading 

use_gevent = True   
use_debug = False   
cycles_count = 100 
if use_gevent: 
    from gevent import monkey 
    monkey.patch_thread() 

count = 0 

class Counter(threading.Thread): 
    def __init__(self, name): 
     self.thread_name = name 
     super(Counter, self).__init__(name=name) 

    def run(self): 
     global count 
     for i in xrange(cycles_count): 
      if use_debug: 
       print '%s:%s' % (self.thread_name, count) 
      if use_gevent: 
       print self.thread_name 
      count = count + 1 

class Infinite(threading.Thread): 
    def run(self): 
     if use_gevent: 
      print 'Infinite ...' 
     while True: 
      pass 


counters = [Counter('thread:%s' % i) for i in range(5)] 
for counter in counters: 
    counter.start() 
infinite = Infinite() 
infinite.start() 
for counter in counters: 
    counter.join() 

print 'count=%s' % count 
+0

gevent는 IO가 발생하지 않기 때문에 gevent가 다른 스레드로 전환하지 않기 때문에 잠금을 사용하지 않고 gevent,'count + = 1'을 사용합니다. 따라서 gevent에서 스레드가 안전한지 '카운트 + = 1'되지 않습니다. 알겠습니까? – onlytiancai

+0

@onlytiancai 나는 당신이 의미하는 것을 이해하지 못합니다. 질문을 재구성 할 수 있습니까? –