Python에서 Lock 제어

세니·2025년 2월 24일
0

회사 작업을 하다가 python 3.8 환경에서 파일에 대한 접근을 관리하기 위해서 Lock 기능을 추가해야 했었던 일이 있었다.

여러 요청들이 온다면 하나의 특정 파일에 대해 이 파일을 읽을 것인지 수정할 것인지 만일 동시에 수정을 한다면 이를 막아야 하는 상황이 있었다.

python에는 여러 잠금을 위한 라이브러리 Filelock, fcntl 등이 있지만 pip 패키지 관리자를 통해서 추가적으로 설치하고 싶지 않았다. 따라서 표준 라이브러리에서 사용이 가능한 fcntl를 먼저 검토해봤다.

fcntl은 파이썬 표준 라이브러리의 유닉스 특정 서비스로 파일 기술자에 대한 파일 및 I/O 제어를 수행한다. 문서에 가보면 fcntl()과 ioctl() 이라는 유닉스 루틴에 대한 인터페이스를 확인해보라고 한다. 한다디로 유닉스에서 사용하는 fcntl과 ioctl과 거의 같다고 이해했다. (파이썬 버전별로 지원하는 기능이 다르긴 함)

실제로 내부 fcntl.pyi 코드를 보면

if sys.platform != 'win32':
	...
	

win32 체제가 아닐경우에만 사용이 가능한것을 볼 수 있다.

그럼 fcntl은 파일 자체에 잠금을 걸 수 있도록 fcntl.flock() 함수를 이용해야 한다.

잠금 연산에도 유닉스 메뉴얼의 flock()을 참고하면 된다.

잠금 연산에는 4가지 cmd 를 사용한다.

  • LOCK_UN : 이미 존재하는 Lock을 해제한다.
  • LOCK_SH : 공유락을 건다.
  • LOCK_EX : 배타락을 건다.
  • LOCK_NB : Lock 요청에 대한 non-blocking을 수행한다.

공유락, 배타락을 간단하게 정리하자면,

공유락은 읽기는 가능하지만 수정은 안되는 것이고, 배타락은 읽기와 수정 모두 동시에 할 수 없는 락이다.

fcntl은 여러 프로세스 간에 파일 접근을 제어한다. 하지만 여러 쓰레드에서는 하나의 코드에 접근하는 것을 막지 못하는 문제가 있다. 하지만 threading의 Lock 객체를 이용하면 스레드간 동기화를 제어할 수 있어 내가 원하는 방식대로 코드를 제어할 수 있다.

threading에는 다양한 객체 Lock, Semaphore가 있는데 굳이 카운팅할 필요없는 뮤텍스 락과 같은 Lock 객체를 이용하기로 했다. (사용하기도 매우 이지함)

threading의 Lock 객체는 코드 영역을 잠금 할 수 있다.

  • acquire() : 잠금을 설정한다.
  • release() : 잠금을 해제한다.
lock = threaind.Lock()

# 1
with lock:

# 2
try:
	lock.acquire()
	
finally:
	lock.release()

1번과 2번은 같이 동작한다. acquire()과 release() 동작을 with 구문을 통해서 코드를 간소화할 수 있다.

난 그래도 코드의 의미를 쉽게 파악 할 수 있도록 try-except를 이용해 acquire() release()를 사용했다.

이를 사용하면 내가 요구하는 여러 동시 요청 쓰레드 별로 코드 영역에 있는 자원 제어가 가능했고 코드 라인수도 줄일 수 있어서 선택했다.

profile
세니는 무엇을 하고 있을까

0개의 댓글