2016-08-31 3 views
1

여러 스레드에서 액세스해야하는 경우 (읽기/쓰기/크기 가져 오기) 파이썬 목록에 잠금 장치가 필요한지 궁금하십니까? Mac에서 Python 2.7 사용하기.다중 스레드 환경에서 Python 2.7 목록을 보호하려면 잠금이 필요합니까?

나는 목록을 보호하기 위해 잠금 장치를 추가하기 위해 프로토 타입을 작성했습니다. 내 코드에서 필요한 경우 또는 모든 문제 (성능 및 기능면에서)가 확실하지 않은 경우 감사.

BTW, 나는 파이썬 사전과 deque에 관해서 멀티 스레드 환경에서 락을 보호 할 필요가 있는지에 관해서도 같은 질문을한다. 감사.

import threading 
import time 
import random 

class checkStatus: 
    def __init__(self): 
     self.message = [] 
     self.lock = threading.Lock() 
    def checkInStatus(self, msg): 
     self.lock.acquire() 
     self.message.append(msg) 
     self.lock.release() 
    def checkOutStatus(self): 
     self.lock.acquire() 
     if len(self.message) > 0: 
      msg = self.message.pop(0) 
     else: 
      msg = 'Queue empty' 
     self.lock.release() 
     return msg 
    def checkMessageStatus(self): 
     self.lock.acquire() 
     size = len(self.message) 
     self.lock.release() 
     return size 

messageQueue = checkStatus() 

class myThread (threading.Thread): 
    def __init__(self, threadID, name): 
     threading.Thread.__init__(self) 
     self.threadID = threadID 
     self.name = name 
    def run(self): 
     global messageQueue 
     while True: 
      time.sleep(1+5*random.random()) 
      print "%s: %s : %s" % (self.name, time.ctime(time.time()), messageQueue.checkMessageStatus()) 
      time.sleep(1 + 5 * random.random()) 
      msg = time.ctime(time.time()) + ' ' + self.name 
      print "%s: %s : check in message, %s" % (self.name, time.ctime(time.time()), msg) 
      messageQueue.checkInStatus(msg) 
      time.sleep(1 + 5 * random.random()) 
      print "%s: %s : check out message, %s" % (self.name, time.ctime(time.time()), messageQueue.checkOutStatus()) 


if __name__ == "__main__": 
    threads = [] 

    # Create new threads 
    thread1 = myThread(1, "Thread-1") 
    thread2 = myThread(2, "Thread-2") 

    # Start new Threads 
    thread1.start() 
    thread2.start() 

    # Add threads to thread list 
    threads.append(thread1) 
    threads.append(thread2) 

    # Wait for all threads to complete 
    for t in threads: 
     t.join() 
    print "Exiting Main Thread" 

출력,

Thread-2: Tue Aug 30 22:08:04 2016 : 0 
Thread-1: Tue Aug 30 22:08:05 2016 : 0 
Thread-1: Tue Aug 30 22:08:07 2016 : check in message, Tue Aug 30 22:08:07 2016 Thread-1 
Thread-2: Tue Aug 30 22:08:07 2016 : check in message, Tue Aug 30 22:08:07 2016 Thread-2 
Thread-2: Tue Aug 30 22:08:09 2016 : check out message, Tue Aug 30 22:08:07 2016 Thread-1 
Thread-1: Tue Aug 30 22:08:11 2016 : check out message, Tue Aug 30 22:08:07 2016 Thread-2 
Thread-2: Tue Aug 30 22:08:11 2016 : 0 
Thread-1: Tue Aug 30 22:08:13 2016 : 0 
Thread-2: Tue Aug 30 22:08:15 2016 : check in message, Tue Aug 30 22:08:15 2016 Thread-2 
Thread-1: Tue Aug 30 22:08:17 2016 : check in message, Tue Aug 30 22:08:17 2016 Thread-1 
Thread-2: Tue Aug 30 22:08:18 2016 : check out message, Tue Aug 30 22:08:15 2016 Thread-2 
Thread-1: Tue Aug 30 22:08:19 2016 : check out message, Tue Aug 30 22:08:17 2016 Thread-1 
+2

멀티 스레딩에서 CPython 구현에는 한 번에 하나의 스레드 만 활성화되도록 GIL (Global Interpreter Lock)이 있습니다. 따라서 자물쇠가 필요하지 않습니다. –

+2

내부적으로 스레드를 멈추고 (가장 안전한 방법) 모든 스레드에 대해'pause','stop','lock' 조건을 만들어야합니다. 추가 상태는'Failed'이고'while True :'는 threading의 악몽입니다. 플래그를 처리하지 않으면 데이터 및 데이터 방식이 손상됩니다. 일부 데이터 또는 프로세스가 스레드에 있지만 '오류 및 오류'발생시 많은 조합을 제외하고 '동기 및 내부 데이터 바인딩'을 제외합니다. – dsgdfg

+0

@ super_cr7, 기본 동작을 변경하는 방법이 있습니까? –

답변

1

귀하의 checkOutStatus 방법이 제대로 작동하는 잠금이 필요합니다; 다른 메소드는 원자 연산을 수행하지 않기 때문에 (간단한 파이썬 문장은 원자 적이다,이 reference을 보라). checkOutStatus에 잠금을 설정하지 않으면 if 문이 True로 평가되지만 self.message.pop(0)으로 메시지를 검색하기 전에 스레드 전환이 즉시 발생하는 경우가있을 수 있습니다. 그런 다음 두 번째 스레드가 메시지를 제거하면 첫 번째 스레드가 계속되면 빈 목록에서 팝업을 시도합니다. 다음과 같이 함수를 다시 작성하는 경우 :

def checkOutStatus(self): 
    try: 
     msg = self.message.pop(0) 
    except IndexError: 
     msg = 'Queue empty' 
    return msg 

유일한 작업은 원자 단위이므로 스레드 안전성을 유지합니다. 이 경우 모든 잠금 코드를 삭제할 수 있습니다.

+0

고마워 Paul,'checkOutStatus'에'self.lock.acquire()'와'self.lock.release()'를 이미 추가했습니다. 내 구현에 문제가 있다는 뜻입니까? –

+1

실제적인 문제는 없습니다. 구현은 작동하지만 잠금을 제거하면 가끔 실패 할 수 있습니다. 당신의 다른 방법은 전혀 자물쇠가 필요하지 않습니다. 내 예제에서는'checkOutStatus'에서 잠금을 제거 할 수도 있습니다. 일반적으로'try : except :'구조가 if 문 접근보다 선호되며, 이것이 이유 중 하나이다. –

+0

물론 고마워요. 하지만 내 혼란은, 우리는 pop 메소드에 대한 자물쇠가 필요하다고 생각하는데, 왜 당신은'checkOutStatus'에 자물쇠를 추가하지 않습니까? 나는 귀하의 의견을 잘못 읽었습니까? –

관련 문제