DrawingProcess
λ“œν”„ DrawingProcess
DrawingProcess
전체 방문자
였늘
μ–΄μ œ
Β«   2025/06   Β»
일 μ›” ν™” 수 λͺ© 금 ν† 
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
  • λΆ„λ₯˜ 전체보기 (967)
    • Profile & Branding (25)
      • Career (18)
    • IT Trends (254)
      • Conference, Faire (Experien.. (31)
      • News (187)
      • Youtube (19)
      • TED (8)
      • Web Page (2)
      • IT: Etc... (6)
    • Contents (97)
      • Book (66)
      • Lecture (31)
    • Project Process (94)
      • Ideation (0)
      • Study Report (34)
      • Challenge & Award (22)
      • 1Day1Process (5)
      • Making (5)
      • KRC-FTC (Team TC(5031, 5048.. (10)
      • GCP (GlobalCitizenProject) (15)
    • Study: ComputerScience(CS) (72)
      • CS: Basic (9)
      • CS: Database(SQL) (5)
      • CS: Network (14)
      • CS: OperatingSystem (3)
      • CS: Linux (39)
      • CS: Etc... (2)
    • Study: Software(SW) (95)
      • SW: Language (29)
      • SW: Algorithms (1)
      • SW: DataStructure & DesignP.. (1)
      • SW: Opensource (15)
      • SW: Error Bug Fix (43)
      • SW: Etc... (6)
    • Study: Artificial Intellige.. (149)
      • AI: Research (1)
      • AI: 2D Vision(Det, Seg, Tra.. (35)
      • AI: 3D Vision (70)
      • AI: MultiModal (3)
      • AI: SLAM (0)
      • AI: Light Weight(LW) (3)
      • AI: Data Pipeline (7)
      • AI: Machine Learning(ML) (1)
    • Study: Robotics(Robot) (33)
      • Robot: ROS(Robot Operating .. (9)
      • Robot: Positioning (8)
      • Robot: Planning & Control (7)
    • Study: DeveloperTools(DevTo.. (83)
      • DevTool: Git (12)
      • DevTool: CMake (13)
      • DevTool: NoSQL(Elastic, Mon.. (25)
      • DevTool: Container (17)
      • DevTool: IDE (11)
      • DevTool: CloudComputing (4)
    • 인생을 μ‚΄λ©΄μ„œ (64)
      • λ‚˜μ˜ μ·¨λ―Έλ“€ (7)
      • λ‚˜μ˜ 생각듀 (42)
      • 여행을 λ– λ‚˜μž~ (10)
      • 뢄기별 회고 (5)

개발자 λͺ…μ–Έ

β€œ λ§€μ£Ό λͺ©μš”μΌλ§ˆλ‹€ 당신이 항상 ν•˜λ˜λŒ€λ‘œ μ‹ λ°œλˆμ„ 묢으면 μ‹ λ°œμ΄ ν­λ°œν•œλ‹€κ³  생각해보라.
컴퓨터λ₯Ό μ‚¬μš©ν•  λ•ŒλŠ” 이런 일이 항상 μΌμ–΄λ‚˜λŠ”λ°λ„ 아무도 λΆˆν‰ν•  생각을 μ•ˆ ν•œλ‹€. ”

- Jef Raskin

λ§₯의 아버지 - μ• ν”Œμ»΄ν“¨ν„°μ˜ λ§€ν‚¨ν† μ‹œ ν”„λ‘œμ νŠΈλ₯Ό 주도

인기 κΈ€

졜근 κΈ€

졜근 λŒ“κΈ€

ν‹°μŠ€ν† λ¦¬

hELLO Β· Designed By μ •μƒμš°.
DrawingProcess

λ“œν”„ DrawingProcess

[Python] Thread: GILκ³Ό Thread κ΅¬ν˜„/μ‹€ν–‰, Event
Study: Software(SW)/SW: Language

[Python] Thread: GILκ³Ό Thread κ΅¬ν˜„/μ‹€ν–‰, Event

2024. 2. 12. 15:32
λ°˜μ‘ν˜•
πŸ’‘ λ³Έ λ¬Έμ„œλŠ” '[Python] Thread: GILκ³Ό Thread κ΅¬ν˜„/μ‹€ν–‰, Event'에 λŒ€ν•΄ 정리해놓은 κΈ€μž…λ‹ˆλ‹€.
~~~μ •λ¦¬ν•˜μ˜€μœΌλ‹ˆ μ°Έκ³ ν•˜μ‹œκΈ° λ°”λžλ‹ˆλ‹€.

1. Thread λ™μž‘

ν”„λ‘œμ„ΈμŠ€μ™€ μŠ€λ ˆλ“œμ—μ„œ μŠ€λ ˆλ“œκ°€ 무엇인지 μ•Œμ•„λ΄€μŠ΅λ‹ˆλ‹€. μ΄λ²ˆμ—λŠ” νŒŒμ΄μ¬μ—μ„œ μŠ€λ ˆλ“œλ₯Ό κ΅¬ν˜„ν•˜κ³  μ‚¬μš©ν•˜λŠ” 기본적인 방법과 μžμ›μ˜ 무결성과 동기화λ₯Ό μœ„ν•œ μ²˜λ¦¬μ— κ΄€ν•΄μ„œ μ•Œμ•„λ³΄λ„λ‘ ν•˜κ² μŠ΅λ‹ˆλ‹€.

GIL(Global Interpreter Lock)

파이썬 μ½”λ“œλŠ” 인터프리터가 μ½”λ“œλ₯Ό λ²ˆμ—­ν•˜κ³  μ‹€ν–‰ν•¨μœΌλ‘œμ¨ μ‹€ν–‰λ©λ‹ˆλ‹€. 즉, 파이썬 μ½”λ“œκ°€ μ‹€ν–‰λ˜κΈ° μœ„ν•΄μ„œλŠ” μΈν„°ν”„λ¦¬ν„°λΌλŠ” μžμ›μ„ μ†Œμœ ν•˜κ³  μžˆμ–΄μ•Ό ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. GIL은 인터프리터가 ν•œ μ‹œμ μ— ν•˜λ‚˜μ˜ μŠ€λ ˆλ“œλ§Œ μ‹€ν–‰ν•  수 μžˆλ„λ‘ ν•΄μ£ΌλŠ” 인터프리터 μ†Œμœ μ— κ΄€ν•œ Lockμž…λ‹ˆλ‹€.

Python의 μŠ€λ ˆλ“œ λ™μž‘

λ©€ν‹°μ½”μ–΄ ν™˜κ²½μ—μ„œ μ—¬λŸ¬κ°œμ˜ μŠ€λ ˆλ“œλ₯Ό λ™μž‘μ‹œν‚¨λ‹€λ©΄ 각각의 μŠ€λ ˆλ“œλ“€μ΄ λ³‘λ ¬μ μœΌλ‘œ λ™μž‘ν•˜λŠ” 것을 μƒκ°ν•˜μ‹€κ²λ‹ˆλ‹€. ν•˜μ§€λ§Œ νŒŒμ΄μ¬μ—μ„œλŠ” GIL둜 인해 인터프리터가 ν•˜λ‚˜μ˜ μŠ€λ ˆλ“œμ— μ˜ν•΄μ„œλ§Œ μ†Œμœ λ  수 μžˆμœΌλ―€λ‘œ μ•„λž˜μ™€ 같은 λ°©μ‹μœΌλ‘œ λ™μž‘ν•˜κ²Œ λ©λ‹ˆλ‹€.

각각의 μŠ€λ ˆλ“œκ°€ GIL을 νšλ“ν•˜μ—¬ λ™μž‘ν•˜κ³  GIL을 λ‹€λ₯Έ μŠ€λ ˆλ“œμ—κ²Œ μ†Œμœ κΆŒμ„ λ„˜κΈ°λ©΄μ„œ λ™μž‘ν•˜κ²Œ λ©λ‹ˆλ‹€. 이와 같은 λ™μž‘ λ°©μ‹μœΌλ‘œ μΈν•˜μ—¬ 파이썬의 경우 μŠ€λ ˆλ“œλ₯Ό λ³‘λ ¬μ μœΌλ‘œ μ²˜λ¦¬ν•  경우 였히렀 GIL을 νšλ“/λ°˜λ‚©ν•˜λŠ” κ³Όμ •μ˜ μ˜€λ²„ν—€λ“œλ‘œ μΈν•˜μ—¬ 였히렀 μ‹€ν–‰μ‹œκ°„μ΄ λŠλ €μ§€κ²Œ λ˜λŠ” λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ™œ GIL을 μ‚¬μš©ν•˜λŠ” 것인가?

νŒŒμ΄μ¬μ—μ„œλŠ” 객체λ₯Ό reference counting을 톡해 garbage collection을 μ‹€ν–‰ν•©λ‹ˆλ‹€. 각 κ°μ²΄λ§ˆλ‹€ 참쑰되고 μžˆλŠ” 횟수λ₯Ό reference count에 μ €μž₯ν•˜κ³ , 이 νšŸμˆ˜κ°€ 0이 되면 garbage collectorκ°€ λ©”λͺ¨λ¦¬λ₯Ό νšŒμˆ˜ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. λ”°λΌμ„œ 이 reference countλŠ” 값이 λ”λŸ½ν˜€μ§€κ²Œ λ˜λŠ” 경우 μ‚¬μš© 쀑인 객체가 μ‚¬λΌμ§€κ±°λ‚˜, μ‚¬μš©λ˜μ§€ μ•ŠλŠ” 객체가 계속 λ©”λͺ¨λ¦¬λ₯Ό μ°¨μ§€ν•˜κ²Œ λ˜λŠ” λ¬Έμ œκ°€ λ°œμƒν•  수 있기 λ•Œλ¬Έμ—, Lock을 톡해 동기화λ₯Ό ν•  ν•„μš”κ°€ μžˆμŠ΅λ‹ˆλ‹€.

ν•˜μ§€λ§Œ μ‚¬μš©λ˜λŠ” λͺ¨λ“  객체에 Lock을 μ‚¬μš©ν•˜μ—¬ 관리할 경우, Lock을 기닀리고 Lock을 νšλ“/λ°˜ν™˜ν•˜λŠ” μ˜€λ²„ν—€λ“œμ™€ Race condition λ“± λ‹€μ–‘ν•œ λ¬Έμ œκ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ Pythonμ—μ„œλŠ” μ• μ΄ˆμ— 인터프리터에 μ „μ—­μ μœΌλ‘œ Lock을 κ±Έμ–΄ ν•˜λ‚˜μ˜ μŠ€λ ˆλ“œλ§Œ 싀행될 수 μžˆλ„λ‘ ν•˜μ—¬ λ‹€λ₯Έ μžμ›μ— λŒ€ν•œ 동기화 문제λ₯Ό ν•΄κ²°ν•œ κ²ƒμž…λ‹ˆλ‹€.

GIL은 CPU Boundμ—λŠ” μ·¨μ•½ν•©λ‹ˆλ‹€. μ•žμ„œ λ§ν–ˆλ“―μ΄ μ—¬λŸ¬ μŠ€λ ˆλ“œκ°€ 인터프리터λ₯Ό μ£Όκ³ λ°›μœΌλ©° μ‹€ν–‰ν•˜κΈ° λ•Œλ¬Έμ— μžμ›μ„ νšλ“/λ°˜ν™˜ν•˜λŠ” κ³Όμ •μ˜ μ˜€λ²„ν—€λ“œλ‘œ μΈν•˜μ—¬ μ‹±κΈ€ μ½”μ–΄ ν™˜κ²½μ—μ„œλ³΄λ‹€ μ„±λŠ₯이 λ”μš± μ•ˆμ’‹μ•„μ§ˆ 수 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€.

ν•˜μ§€λ§Œ GIL으둜 μΈν•œ μž₯점도 λΆ„λͺ…νžˆ μ‘΄μž¬ν•©λ‹ˆλ‹€. I/O Bound의 경우 I/O μž‘μ—…μ‹œμ—λŠ” GIL을 λ°˜ν™˜ν•˜μ—¬ λ‹€λ₯Έ μŠ€λ ˆλ“œκ°€ λ™μž‘ν•  수 μžˆλ„λ‘ ν•˜μ—¬ μ„±λŠ₯이 κ°œμ„ λ  수 있으며, μ„Έμ„Έν•˜κ²Œ Lock을 μ„€κ³„ν•˜μ§€ μ•Šμ•„λ„ 되기 λ•Œλ¬Έμ— κ΅¬ν˜„μ—μ„œ 훨씬 κ°„νŽΈν•©λ‹ˆλ‹€.

2. Thread κ΅¬ν˜„

νŒŒμ΄μ¬μ—μ„œ μŠ€λ ˆλ“œλ₯Ό κ΅¬ν˜„ν•˜λŠ” λ°©λ²•μ—λŠ” μ €μˆ˜μ€€ 라이브러리, κ³ μˆ˜μ€€ 라이브러리λ₯Ό μ‚¬μš©ν•˜λŠ” 방법이 μžˆμŠ΅λ‹ˆλ‹€. μ €μˆ˜μ€€μ˜ 라이브러리λ₯Ό μ‚¬μš©ν•˜κ²Œ 되면 thread poolμ΄λ‚˜ lock을 μ»€μŠ€ν„°λ§ˆμ΄μ§•ν•˜μ—¬ μ‚¬μš©ν•  수 있고, μŠ€λ ˆλ“œμ˜ μ›μ‹œμ μΈ κΈ°λŠ₯듀을 μ›ν•˜λŠ”λŒ€λ‘œ λ³€κ²½ν•˜μ—¬ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ κ΅¬ν˜„μ΄ μ–΄λ ΅κ³  lock의 섀계λ₯Ό ν•΄μ£Όμ–΄μ•Όν•œλ‹€λŠ” 단점이 μžˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ 일반적으둜 많이 μ‚¬μš©ν•˜λŠ” κ³ μˆ˜μ€€μ˜ 라이브러리인 treading λͺ¨λ“ˆμ„ μ‚¬μš©ν•˜μ—¬ Threadλ₯Ό κ΅¬ν˜„ν•˜λŠ” 방법을 μ•Œμ•„λ³΄λ„λ‘ ν•˜κ² μŠ΅λ‹ˆλ‹€.

1) ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•œ Thread κ΅¬ν˜„

import threading
import time

def work(count):
    time.sleep(0.1)
    print("\nname : %s\nargument : %s\n"%(threading.currentThread().getName(), count))
    # μŠ€λ ˆλ“œ μƒμ„±μ‹œ 인자둜 받은 name,count 좜λ ₯

def main():
    for i in range(5):
        t = threading.Thread(target=work, name="thread %i"%i, args=(i,))
        t.start()

if __name__=="__main__":
    main()

ν•¨μˆ˜λ₯Ό μŠ€λ ˆλ“œλ‘œ λ§Œλ“€μ–΄ μ‹€ν–‰ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€. threading λͺ¨λ“ˆμ˜ Thread 클래슀λ₯Ό μ‚¬μš©ν•˜μ—¬ thread 객체λ₯Ό λ§Œλ“€μ–΄ start() λ©”μ†Œλ“œλ‘œ μ‹€ν–‰ν•˜λ©΄ λ©λ‹ˆλ‹€. target μΈμžλ‘œλŠ” μŠ€λ ˆλ“œλ‘œ κ΅¬ν˜„ν•  ν•¨μˆ˜λ₯Ό 인자둜 μ „λ‹¬ν•˜κ³ , name 인자둜 ν•΄λ‹Ή μŠ€λ ˆλ“œμ˜ 이름을 ν• λ‹Ήν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ argsλ₯Ό 톡해 μŠ€λ ˆλ“œλ‘œ κ΅¬ν˜„ν•  ν•¨μˆ˜μ— ν•„μš”ν•œ μΈμžλ“€μ„ 전달할 수 μžˆμŠ΅λ‹ˆλ‹€.

name : thread 1 
argument : 1

name : thread 2 
argument : 2

name : thread 0 
argument : 0

name : thread 3 
argument : 3

name : thread 4 
argument : 4

μœ„μ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜κ²Œ 되면 μœ„μ²˜λŸΌ thread둜 κ΅¬ν˜„ν•œ λ©”μ†Œλ“œλ“€μ΄ λΉ„μˆœμ°¨μ μœΌλ‘œ μ‹€ν–‰λœ κ²°κ³Όλ₯Ό 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

2) 클래슀λ₯Ό μ‚¬μš©ν•œ Thread κ΅¬ν˜„

import threading


class Work(threading.Thread):				# Thread 상속

    def __init__(self, args, name=""):		# μƒμ„±μž κ΅¬ν˜„
        threading.Thread.__init__(self, name=name)
        self.args = args

    def run(self):							# run λ©”μ†Œλ“œ κ΅¬ν˜„
        print("\nname : %s\nargument : %s\n"%(threading.currentThread().getName(), self.args[0]))

def main():
    for i in range(5):
        t = Work(name="thread % i"%i, args=(i,))
        t.start()

if __name__=="__main__":
    main()

클래슀λ₯Ό μ‚¬μš©ν•˜μ—¬ threadλ₯Ό κ΅¬ν˜„ν•˜λŠ” 방법도 κ°„λ‹¨ν•©λ‹ˆλ‹€. treadingλͺ¨λ“ˆμ˜ Thread 클래슀λ₯Ό 상속 받은 λ‹€μŒ run λ©”μ†Œλ“œλ₯Ό κ΅¬ν˜„ν•˜λ©΄ λ©λ‹ˆλ‹€. μƒμ„±μžλ₯Ό κ΅¬ν˜„ν•˜λŠ” κ²½μš°μ—λŠ” Thread둜 κ΅¬ν˜„ν•  클래슀 μƒμ„±μž λ‚΄λΆ€μ—μ„œ Thread 클래슀의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•΄μ•Ό ν•©λ‹ˆλ‹€.

μŠ€λ ˆλ“œ 객체가 start λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ λ‚΄λΆ€μ μœΌλ‘œ run λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜κ²Œ λ©λ‹ˆλ‹€. λ”°λΌμ„œ μŠ€λ ˆλ“œμ—μ„œ λ™μž‘μ‹œν‚¬ λ‘œμ§μ„ run λ©”μ†Œλ“œμ— κ΅¬ν˜„ν•˜λ©΄ λ©λ‹ˆλ‹€.

name : thread  0
argument : 0

name : thread  1
argument : 1

name : thread  4
argument : 4

name : thread  2
argument : 2

name : thread  3
argument : 3

3) Daemon Thread

μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ°±κ·ΈλΌμš΄λ“œμ—μ„œ λ™μž‘ν•˜μ—¬ μ—¬λŸ¬ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 데λͺ¬μ„ κ΅¬ν˜„ν•˜μ—¬ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ£Όμš” μž‘μ—…λ“€μ€ main μŠ€λ ˆλ“œμ—μ„œ μˆ˜ν–‰ν•˜κ³ , λ°±κ·ΈλΌμš΄λ“œλ‘œ μ‹€ν–‰ν•  μž‘μ—…μ„ μŠ€λ ˆλ“œλ‘œ κ΅¬ν˜„ν•˜μ—¬ 데λͺ¬μœΌλ‘œ λ™μž‘μ‹œν‚€λŠ” κ²ƒμž…λ‹ˆλ‹€.

import threading
import time
import logging

logging.basicConfig(level=logging.DEBUG, format="(%(threadName)s) %(message)s")

def daemon_work():
    logging.debug("Start")
    time.sleep(3)							# 3.main thread 둜 Lock λ„˜κΉ€
    logging.debug("Exit")
    
def main():
    t = threading.Thread(name="daemon work", target=daemon_work)
    t.setDaemon(True)						# 1.Daemon thread둜 μ„€μ •
    
    t.start()								# 2.Daemon thread μ‹€ν–‰
    logging.debug("Back to main thread")	# 4.main thread μ’…λ£Œ
    
if __name__=="__main__":
	main()

μœ„λŠ” 데λͺ¬ μŠ€λ ˆλ“œλ₯Ό κ΅¬ν˜„ν•˜μ—¬ μ‹€ν–‰ν•˜λŠ” μ½”λ“œμž…λ‹ˆλ‹€. 데λͺ¬ μŠ€λ ˆλ“œλ₯Ό κ΅¬ν˜„ν•˜λŠ” 방법은 κ°„λ‹¨ν•©λ‹ˆλ‹€. μŠ€λ ˆλ“œμ˜ setDaemon(boolean)λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ 데λͺ¬μœΌλ‘œ μ„€μ •ν•΄μ£Όλ©΄ λ©λ‹ˆλ‹€. μœ„μ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜κ²Œ 되면 μ•„λž˜μ™€ 같은 κ²°κ³Όκ°€ 좜λ ₯되게 λ©λ‹ˆλ‹€.

(daemon work) Start
(MainThread) Back to main thread

Daemon Thread와 Thread의 차이

μœ„μ˜ μ½”λ“œμ˜ 좜λ ₯ κ²°κ³Όλ₯Ό λ³΄μ‹œλ©΄ μ΄μƒν•œ 점이 μžˆμŠ΅λ‹ˆλ‹€. 데λͺ¬ μŠ€λ ˆλ“œμ˜ λ§ˆμ§€λ§‰ λ‘œκΉ…μ΄ μ‹€ν–‰λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. κ·Έ μ΄μœ λŠ” 데λͺ¬ μŠ€λ ˆλ“œμ˜ 경우 메인 ν”„λ‘œκ·Έλž¨ 둜직이 μ’…λ£Œλ˜λ©΄ μžλ™μœΌλ‘œ μ’…λ£Œλ˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

μŠ€λ ˆλ“œμ˜ 경우, 메인 ν”„λ‘œκ·Έλž¨μ˜ 둜직이 μ’…λ£Œλ˜λ”λΌλ„ μŠ€λ ˆλ“œκ°€ μ’…λ£Œλ˜μ§€ μ•ŠλŠ”λ‹€λ©΄ μŠ€λ ˆλ“œκ°€ μ’…λ£Œλ  λ•ŒκΉŒμ§€ 메인 ν”„λ‘œκ·Έλž¨μ€ μ’…λ£Œλ˜μ§€ μ•Šκ³  κΈ°λ‹€λ¦¬κ²Œ λ©λ‹ˆλ‹€. λ”°λΌμ„œ 일정 μ£ΌκΈ°λ§ˆλ‹€ λ™μž‘μ„ λ°˜λ³΅ν•˜λŠ” μž‘μ—…μ„ κ΅¬ν˜„ν•  λ•Œ, 일반 μŠ€λ ˆλ“œλ‘œ κ΅¬ν˜„ν•˜κ²Œ 되면 μž‘μ—…μ„ 적절히 μ’…λ£Œμ‹œν‚€λŠ” μž‘μ—…μ„ λ³„λ„λ‘œ κ΅¬ν˜„ν•΄μ•Όν•©λ‹ˆλ‹€.

ν•˜μ§€λ§Œ 데λͺ¬ μŠ€λ ˆλ“œλŠ” 메인 ν”„λ‘œκ·Έλž¨ 둜직이 μ’…λ£Œλœλ‹€λ©΄ 데λͺ¬ μŠ€λ ˆλ“œλ„ μžλ™μœΌλ‘œ μ’…λ£Œλ©λ‹ˆλ‹€. λ”°λΌμ„œ 데λͺ¬ μŠ€λ ˆλ“œλ₯Ό μ’…λ£Œμ‹œν‚€κΈ° μœ„ν•œ λ³„λ„μ˜ 처리λ₯Ό μ‹ κ²½μ“°μ§€ μ•Šμ•„λ„ λ©λ‹ˆλ‹€. μ΄λŸ¬ν•œ 점으둜 μΈν•˜μ—¬ μŠ€λ ˆλ“œμ— μ ‘κ·Όν•˜κΈ° μ–΄λ ΅κ³  μ˜λ„λŒ€λ‘œ μ’…λ£Œμ‹œν‚€κΈ° μ–΄λ €μš΄ 점이 μžˆμŒμ—λ„ 데λͺ¬ μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ°±κ·ΈλΌμš΄λ“œ λ™μž‘μ„ κ΅¬ν˜„ν•©λ‹ˆλ‹€.

Daemon Thread μž‘μ—… μ’…λ£Œ 기닀리기

데λͺ¬ μŠ€λ ˆλ“œλŠ” 메인 ν”„λ‘œκ·Έλž¨μ˜ 둜직이 μ’…λ£Œλ˜λ©΄ μžλ™μœΌλ‘œ μ’…λ£Œλœλ‹€κ³  μ„€λͺ…ν•˜μ˜€μŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ ν”„λ‘œκ·Έλž¨μ— λ”°λΌμ„œ 데λͺ¬ μŠ€λ ˆλ“œμ˜ μž‘μ—…μ΄ μ’…λ£Œλ˜μ–΄μ•Ό ν”„λ‘œκ·Έλž¨μ„ μ’…λ£Œ ν•΄μ•Όν•  κ²½μš°κ°€ μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ 경우 join()을 μ΄μš©ν•˜μ—¬ 데λͺ¬ μŠ€λ ˆλ“œκ°€ μ’…λ£Œλ˜λ©΄ ν”„λ‘œκ·Έλž¨μ„ μ’…λ£Œν•  수 μžˆλ„λ‘ κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

def daemon_work():
    logging.debug("Start")
    time.sleep(3)							# 3.main thread 둜 Lock λ„˜κΉ€
    logging.debug("Exit")
    
def main():
    t = threading.Thread(name="daemon work", target=daemon_work)
    t.setDaemon(True)						# 1.Daemon thread둜 μ„€μ •
    
    t.start()								# 2.Daemon thread μ‹€ν–‰
    logging.debug("Back to main thread")	# 4.main thread μ’…λ£Œ
    t.join()								# 5.Daemon thread μ’…λ£Œ λŒ€κΈ°
    
if __name__=="__main__":
	main()

μœ„μ™€ λ˜‘κ°™μ€ ν”„λ‘œκ·Έλž¨μ— λ§ˆμ§€λ§‰ join() λ©”μ†Œλ“œλ§Œ μΆ”κ°€ν•˜μ˜€μŠ΅λ‹ˆλ‹€. 이처럼 join()λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ˜λ„ν•œλŒ€λ‘œ 데λͺ¬ μŠ€λ ˆλ“œκ°€ μ’…λ£Œλ˜κ³  메인 ν”„λ‘œκ·Έλž¨μ„ μ’…λ£Œν•˜λ„λ‘ κ΅¬ν˜„ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

(daemon work) Start
(MainThread) Back to main thread
(daemon work) Exit

4) Thread Event

파이썬 threading λͺ¨λ“ˆμ—μ„œλŠ” μŠ€λ ˆλ“œ κ°„μ˜ κ°„λ‹¨ν•œ 톡신을 μœ„ν•΄ Eventλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. μŠ€λ ˆλ“œμ˜ EventλŠ” 이벀트λ₯Ό μ„€μ •, μ΄ˆκΈ°ν™”, κΈ°λ‹€λ¦¬λŠ” λ™μž‘μ„ μ œκ³΅ν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ λ™μž‘λ“€μ„ μŠ€λ ˆλ“œμ—μ„œ μ‚¬μš©ν•˜μ—¬ νŠΉμ • 쑰건에 따라 μŠ€λ ˆλ“œλ₯Ό λ™μž‘μ‹œν‚€λ„λ‘ μ œμ–΄ν•˜λŠ”λ° μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

thread κ°„μ˜ κ°„λ‹¨ν•œ 톡신을 μœ„ν•΄ μ‚¬μš©λ˜λŠ” 객체

  • is_set() : λ‚΄λΆ€ ν”Œλž˜κ·Έκ°€ Trueλ©΄ κ·Έλ•Œλ§Œ True λ°˜ν™˜
  • set() : λ‚΄λΆ€ ν”Œλž˜κ·Έλ₯Ό True둜 μ„€μ •
  • clear() : λ‚΄λΆ€ ν”Œλž˜κ·Έλ₯Ό False둜 μ„€μ •
  • wait(timeout=None) : λ‚΄λΆ€ ν”Œλž˜κ·Έκ°€ Trueκ°€ λ λ•ŒκΉŒμ§€ blocking함. 

e.g.

import time
import logging
import threading


logging.basicConfig(level=logging.DEBUG, format="(%(threadName)s) %(message)s")

def thread1(e1, e2):
    while not e1.isSet():
        event = e1.wait(1)
        logging.debug("Event status : (%s)", event)

        if event:
            logging.debug("e1 is set.")
            time.sleep(3)
            logging.debug("setting event e2")
            e2.set()

def thread2(e2):
    while not e2.isSet():
        event = e2.wait(1)
        logging.debug("Event status : (%s)", event)

        if event:
            logging.debug("e2 is set.")

def main():
    e1 = threading.Event()
    e2 = threading.Event()

    t1 = threading.Thread(name="First Thread", target=thread1, args=(e1, e2))
    t1.start()
    t2 = threading.Thread(name="Second Thread", target=thread2, args=(e2,))
    t2.start()

    logging.debug("wait ...")
    time.sleep(5)                   # λ‹€λ₯Έ μŠ€λ ˆλ“œλ‘œ Lock λ°˜ν™˜
    logging.debug("set event e1")
    e1.set()
    time.sleep(5)
    logging.debug("Exit")

if __name__=="__main__":
    main()

μœ„ ν”„λ‘œκ·Έλž¨μ˜ λ™μž‘μ„ 흐름에 따라 μ •λ¦¬ν•˜λ©΄ μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

메인 μŠ€λ ˆλ“œμ—μ„œ 이벀트인 e1, e2와 μŠ€λ ˆλ“œμΈ t1, t2λ₯Ό 각각 μƒμ„±ν•˜κ³ , "wait ..."문을 λ‘œκΉ…ν•˜λŠ” μ½”λ“œλ₯Ό λ™μž‘ν•˜κ²Œ λ©λ‹ˆλ‹€. 그리고 time.sleep(5)μ—μ„œ λ‹€λ₯Έ μŠ€λ ˆλ“œκ°€ λ™μž‘ν•˜κ²Œ 되고, t1κ³Ό t2κ°€ λ°˜λ³΅ν•˜μ—¬ λ™μž‘ν•˜μ§€λ§Œ e1κ³Ό e2κ°€ μ„€μ •λ˜μ§€ μ•Šμ•„ isSet()λ¬Έμ—μ„œ Falseλ₯Ό λ°˜ν™˜ν•˜μ—¬ if event λΈ”둝을 μ‹€ν–‰ν•˜μ§€ λͺ»ν•˜λ©° t1,t2κ°€ λ²ˆκ°ˆμ•„κ°€λ©° λ™μž‘ν•˜κ²Œ λ©λ‹ˆλ‹€.

그러던 쀑, 메인 μŠ€λ ˆλ“œμ˜ time.sleep(5) λ™μž‘이 λλ‚˜κ³  λ‹€μ‹œ Lock을 λŒ€κΈ°ν•˜μ—¬ νšλ“ν•œ ν›„, e1을 setν•œ ν›„ λ‹€μ‹œ sleep문을 λ§Œλ‚˜ Lock을 λ°˜λ‚©ν•˜κ²Œ λ©λ‹ˆλ‹€. 그러면 λ‹€μ‹œ t1μ—μ„œ Lock을 νšλ“ν•˜μ—¬ λ™μž‘ν•˜κ²Œ 되고, isSet()μ—μ„œ Trueλ₯Ό λ°˜ν™˜ν•˜μ—¬ e2의 이벀트λ₯Ό setν•˜λŠ” λ‘œμ§μ„ μˆ˜ν–‰ν•˜κ²Œ λ©λ‹ˆλ‹€.

λ‹€μŒμœΌλ‘œλŠ” t2μ—μ„œλ„ isSet()이 Trueλ₯Ό λ°˜ν™˜ν•˜κ³ , μŠ€λ ˆλ“œλ₯Ό μ’…λ£Œν•˜λ©° 메인 μŠ€λ ˆλ“œκ°€ μ‹€ν–‰λ˜λ©° ν”„λ‘œκ·Έλž¨μ΄ μ’…λ£Œλ˜κ²Œ λ©λ‹ˆλ‹€.

(MainThread) wait ...
(First Thread) Event status : (False)
(Second Thread) Event status : (False)
...
(MainThread) set event e1
(First Thread) Event status : (True)
(First Thread) e1 is set.
(Second Thread) Event status : (False)
...
(First Thread) setting event e2
(Second Thread) Event status : (True)
(Second Thread) e2 is set.
(MainThread) Exit

이처럼 threading λͺ¨λ“ˆμ—μ„œ μ œκ³΅ν•˜λŠ” Eventλ₯Ό μ‚¬μš©ν•˜μ—¬ μ—¬λŸ¬ μŠ€λ ˆλ“œκ°€ ν†΅μ‹ ν•˜λ©° 각 μŠ€λ ˆλ“œλ“€μ˜ μ‹€ν–‰ 흐름을 μ œμ–΄ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이와 같은 μ΄λ²€νŠΈλŠ” ν”„λ‘œκ·Έλž¨μ˜ 흐름을 μ œμ–΄ν•˜μ—¬ 잘λͺ» μ‚¬μš©ν•˜λŠ” 경우 ν”„λ‘œκ·Έλž¨μ΄ 루프에 λΉ μ§€κ±°λ‚˜ 잘λͺ»λœ νλ¦„λŒ€λ‘œ 싀행될 수 μžˆμœΌλ―€λ‘œ λ©΄λ°€νžˆ λΆ„μ„ν•˜κ³  μ„€κ³„ν•˜μ—¬ μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

μ°Έκ³ 

  • [Blog] 동기화λ₯Ό μœ„ν•œ threading.Event(): https://kinggodrobotics.tistory.com/9
  • https://ssungkang.tistory.com/entry/python-GIL-Global-interpreter-Lock%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C
  •  https://it-eldorado.tistory.com/160 
λ°˜μ‘ν˜•
μ €μž‘μžν‘œμ‹œ λΉ„μ˜λ¦¬ λ³€κ²½κΈˆμ§€ (μƒˆμ°½μ—΄λ¦Ό)

'Study: Software(SW) > SW: Language' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

[Python] Multithreading κ΅¬ν˜„ (feat. 2 Scripts in Parallel(threading λͺ¨λ“ˆ), Producer-consumer Pattern(concurrent λͺ¨λ“ˆ))  (1) 2024.02.09
[Error Fix] JAVA μž¬μ„€μΉ˜ ν›„ 링킹 문제 (feat. JAVA 버전 λ³€κ²½)  (2) 2023.01.20
[JAVA] JVM vs JDK vs JRE? (java와 javac의 버전 및 μ„€μΉ˜κ²½λ‘œ μ•Œμ•„λ³΄κΈ°)  (0) 2023.01.19
[C++] C++ #include ν—€λ”νŒŒμΌ μˆœμ„œ  (0) 2023.01.17
[Rust] Rustκ°€ λœ¨λŠ” 이유 및 문법 νŠΉμ§•  (0) 2023.01.07
    'Study: Software(SW)/SW: Language' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€
    • [Python] Multithreading κ΅¬ν˜„ (feat. 2 Scripts in Parallel(threading λͺ¨λ“ˆ), Producer-consumer Pattern(concurrent λͺ¨λ“ˆ))
    • [Error Fix] JAVA μž¬μ„€μΉ˜ ν›„ 링킹 문제 (feat. JAVA 버전 λ³€κ²½)
    • [JAVA] JVM vs JDK vs JRE? (java와 javac의 버전 및 μ„€μΉ˜κ²½λ‘œ μ•Œμ•„λ³΄κΈ°)
    • [C++] C++ #include ν—€λ”νŒŒμΌ μˆœμ„œ
    DrawingProcess
    DrawingProcess
    과정을 그리자!

    ν‹°μŠ€ν† λ¦¬νˆ΄λ°”