ವಿಷಯಕ್ಕೆ ತೆರಳಿ

ಪೈಥಾನ್ ಮಲ್ಟಿಥ್ರೆಡಿಂಗ್: ಸಂದರ್ಶನ ಪ್ರಶ್ನೆಗಳು

1. ಮಲ್ಟಿಥ್ರೆಡಿಂಗ್ (Multithreading) ಎಂದರೇನು?

ಉತ್ತರ: ಮಲ್ಟಿಥ್ರೆಡಿಂಗ್ ಎನ್ನುವುದು ಒಂದೇ ಪ್ರೊಸೆಸ್‌ನೊಳಗೆ ಹಲವಾರು ಥ್ರೆಡ್‌ಗಳನ್ನು (ಸಣ್ಣ ಎಕ್ಸಿಕ್ಯೂಶನ್ ಯೂನಿಟ್‌ಗಳು) ಏಕಕಾಲದಲ್ಲಿ ( concurrently) ರನ್ ಮಾಡುವ ಪ್ರಕ್ರಿಯೆ. ಪ್ರತಿಯೊಂದು ಥ್ರೆಡ್ ತನ್ನದೇ ಆದ ಎಕ್ಸಿಕ್ಯೂಶನ್ ಸ್ಟಾಕ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ, ಆದರೆ ಅವು ಪ್ರೊಸೆಸ್‌ನ ಮೆಮೊರಿ ಮತ್ತು ರಿಸೋರ್ಸ್‌ಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳುತ್ತವೆ.

ಉಪಯೋಗ:

  • I/O-ಬೌಂಡ್ ಟಾಸ್ಕ್‌ಗಳಿಗೆ: ನೆಟ್‌ವರ್ಕ್ ರಿಕ್ವೆಸ್ಟ್‌ಗಳು, ಫೈಲ್ ಆಪರೇಷನ್‌ಗಳಂತಹ ಸಮಯ ತೆಗೆದುಕೊಳ್ಳುವ I/O ಆಪರೇಷನ್‌ಗಳಿಗಾಗಿ ಕಾಯುತ್ತಿರುವಾಗ, ಬೇರೆ ಥ್ರೆಡ್‌ಗಳು ತಮ್ಮ ಕೆಲಸವನ್ನು ಮುಂದುವರಿಸಬಹುದು. ಇದು ಅಪ್ಲಿಕೇಶನ್‌ನ ರೆಸ್ಪಾನ್ಸಿವ್‌ನೆಸ್ ಅನ್ನು ಸುಧಾರಿಸುತ್ತದೆ.

2. ಪ್ರೊಸೆಸ್ (Process) ಮತ್ತು ಥ್ರೆಡ್ (Thread) ನಡುವಿನ ವ್ಯತ್ಯಾಸವೇನು?

ಉತ್ತರ:

ಲಕ್ಷಣ ಪ್ರೊಸೆಸ್ (Process) ಥ್ರೆಡ್ (Thread)
ವ್ಯಾಖ್ಯಾನ ಪ್ರೋಗ್ರಾಂನ ಒಂದು ರನ್ನಿಂಗ್ ಇನ್‌ಸ್ಟೆನ್ಸ್. ಪ್ರೊಸೆಸ್‌ನೊಳಗಿನ ಒಂದು ಸಣ್ಣ ಎಕ್ಸಿಕ್ಯೂಶನ್ ಯೂನಿಟ್.
ಮೆಮೊರಿ ಪ್ರತಿ ಪ್ರೊಸೆಸ್‌ಗೆ ತನ್ನದೇ ಆದ ಪ್ರತ್ಯೇಕ ಮೆಮೊರಿ ಸ್ಪೇಸ್ ಇರುತ್ತದೆ. ಒಂದೇ ಪ್ರೊಸೆಸ್‌ನ ಎಲ್ಲಾ ಥ್ರೆಡ್‌ಗಳು
ಮೆಮೊರಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳುತ್ತವೆ.
ರಚನೆ ಪ್ರೊಸೆಸ್ ರಚಿಸಲು ಹೆಚ್ಚು ಸಮಯ ಮತ್ತು ರಿಸೋರ್ಸ್ ಬೇಕು. ಥ್ರೆಡ್ ರಚಿಸಲು ಕಡಿಮೆ ಸಮಯ ಮತ್ತು ರಿಸೋರ್ಸ್ ಬೇಕು.
ಸಂವಹನ ಪ್ರೊಸೆಸ್‌ಗಳ ನಡುವಿನ ಸಂವಹನ (IPC) ಕಷ್ಟ ಮತ್ತು ನಿಧಾನ. ಥ್ರೆಡ್‌ಗಳ ನಡುವಿನ ಸಂವಹನ ಸುಲಭ ಮತ್ತು ವೇಗ, ಏಕೆಂದರೆ ಅವು
ಮೆಮೊರಿ ಹಂಚಿಕೊಳ್ಳುತ್ತವೆ.
ದೋಷ ಒಂದು ಪ್ರೊಸೆಸ್ ಕ್ರ್ಯಾಶ್ ಆದರೆ, ಬೇರೆ ಪ್ರೊಸೆಸ್‌ಗಳ ಮೇಲೆ ಪರಿಣಾಮ ಬೀರುವುದಿಲ್ಲ. ಒಂದು ಥ್ರೆಡ್ ಕ್ರ್ಯಾಶ್ ಆದರೆ, ಸಂಪೂರ್ಣ
ಪ್ರೊಸೆಸ್ ಕ್ರ್ಯಾಶ್ ಆಗಬಹುದು.

3. GIL (Global Interpreter Lock) ಎಂದರೇನು?

ಉತ್ತರ: GIL ಎನ್ನುವುದು CPython (ಪೈಥಾನ್‌ನ ಡೀಫಾಲ್ಟ್ ಇಂಪ್ಲಿಮೆಂಟೇಶನ್) ನಲ್ಲಿರುವ ಒಂದು ಮ್ಯೂಟೆಕ್ಸ್ (mutex). ಇದು ಒಂದು ಸಮಯದಲ್ಲಿ ಒಂದೇ ಒಂದು ಥ್ರೆಡ್ ಮಾತ್ರ ಪೈಥಾನ್ ಬೈಟ್‌ಕೋಡ್ ಅನ್ನು ಎಕ್ಸಿಕ್ಯೂಟ್ ಮಾಡುವಂತೆ ಖಚಿತಪಡಿಸುತ್ತದೆ.

ಪರಿಣಾಮ:

  • CPU-ಬೌಂಡ್ ಟಾಸ್ಕ್‌ಗಳಿಗೆ: ಗಣಿತದ ಲೆಕ್ಕಾಚಾರಗಳಂತಹ CPU-ತೀವ್ರವಾದ ಕೆಲಸಗಳಲ್ಲಿ, GIL ನಿಂದಾಗಿ ಮಲ್ಟಿಥ್ರೆಡಿಂಗ್ ನಿಜವಾದ ಪ್ಯಾರಲಲಿಸಂ ಅನ್ನು ನೀಡುವುದಿಲ್ಲ. ಇದರಿಂದಾಗಿ, ಮಲ್ಟಿಥ್ರೆಡಿಂಗ್ ಪ್ರೋಗ್ರಾಂ ಸಿಂಗಲ್-ಥ್ರೆಡೆಡ್ ಪ್ರೋಗ್ರಾಂ ಗಿಂತ ನಿಧಾನವಾಗಿರಬಹುದು.
  • I/O-ಬೌಂಡ್ ಟಾಸ್ಕ್‌ಗಳಿಗೆ: ಒಂದು ಥ್ರೆಡ್ I/O ಗಾಗಿ ಕಾಯುತ್ತಿರುವಾಗ, GIL ಅನ್ನು ಬಿಡುಗಡೆ ಮಾಡುತ್ತದೆ, ಇದರಿಂದ ಬೇರೆ ಥ್ರೆಡ್ ರನ್ ಆಗಬಹುದು. ಆದ್ದರಿಂದ, I/O-ಬೌಂಡ್ ಟಾಸ್ಕ್‌ಗಳಿಗೆ ಮಲ್ಟಿಥ್ರೆಡಿಂಗ್ ಪರಿಣಾಮಕಾರಿಯಾಗಿದೆ.

4. ರೇಸ್ ಕಂಡೀಶನ್ (Race Condition) ಎಂದರೇನು? ಇದನ್ನು ಹೇಗೆ ತಡೆಯುವುದು?

ಉತ್ತರ: ರೇಸ್ ಕಂಡೀಶನ್ ಎನ್ನುವುದು ಹಲವಾರು ಥ್ರೆಡ್‌ಗಳು ಒಂದೇ ಶೇರ್ಡ್ ರಿಸೋರ್ಸ್ ಅನ್ನು (ಉದಾ: ವೇರಿಯೇಬಲ್) ಏಕಕಾಲದಲ್ಲಿ ಆಕ್ಸೆಸ್ ಮಾಡಲು ಮತ್ತು ಬದಲಾಯಿಸಲು ಪ್ರಯತ್ನಿಸಿದಾಗ ಸಂಭವಿಸುವ ಒಂದು ದೋಷ. ಎಕ್ಸಿಕ್ಯೂಶನ್‌ನ ಅಂತಿಮ ಫಲಿತಾಂಶವು ಥ್ರೆಡ್‌ಗಳು ಯಾವ ಕ್ರಮದಲ್ಲಿ ರನ್ ಆಗುತ್ತವೆ ಎಂಬುದರ ಮೇಲೆ ಅವಲಂಬಿತವಾಗಿರುತ್ತದೆ, ಇದು ಅನಿರೀಕ್ಷಿತ ಫಲಿತಾಂಶಗಳಿಗೆ ಕಾರಣವಾಗುತ್ತದೆ.

ತಡೆಯುವ ವಿಧಾನ (ಸಿಂಕ್ರೊನೈಸೇಶನ್): threading ಮಾಡ್ಯೂಲ್‌ನಲ್ಲಿರುವ ಲಾಕ್ಸ್ (Locks) ಬಳಸಿ ರೇಸ್ ಕಂಡೀಶನ್‌ಗಳನ್ನು ತಡೆಯಬಹುದು.

  • ಲಾಕ್ (Lock): ಒಂದು ಸಮಯದಲ್ಲಿ ಒಂದೇ ಒಂದು ಥ್ರೆಡ್ ಮಾತ್ರ ಕೋಡ್‌ನ ನಿರ್ಣಾಯಕ ಭಾಗವನ್ನು (critical section) ಪ್ರವೇಶಿಸುವಂತೆ ಲಾಕ್ ಖಚಿತಪಡಿಸುತ್ತದೆ.
  • acquire(): ಲಾಕ್ ಅನ್ನು ಪಡೆಯಲು ಪ್ರಯತ್ನಿಸುತ್ತದೆ. ಲಾಕ್ ಲಭ್ಯವಿದ್ದರೆ, ಥ್ರೆಡ್ ಮುಂದುವರಿಯುತ್ತದೆ. ಇಲ್ಲದಿದ್ದರೆ, ಲಾಕ್ ಬಿಡುಗಡೆಯಾಗುವವರೆಗೆ ಕಾಯುತ್ತದೆ.
  • release(): ಲಾಕ್ ಅನ್ನು ಬಿಡುಗಡೆ ಮಾಡುತ್ತದೆ, ಇದರಿಂದ ಬೇರೆ ಥ್ರೆಡ್ ಅದನ್ನು ಪಡೆಯಬಹುದು.

ಉದಾಹರಣೆ:

import threading

balance = 0
lock = threading.Lock()


def deposit(amount):
    global balance
    for _ in range(100000):
        lock.acquire()
        balance += amount
        lock.release()


t1 = threading.Thread(target=deposit, args=(1,))
t2 = threading.Thread(target=deposit, args=(1,))

t1.start()
t2.start()
t1.join()
t2.join()

print(balance)  # ಲಾಕ್ ಇಲ್ಲದಿದ್ದರೆ, ಫಲಿತಾಂಶ 200000 ಕ್ಕಿಂತ ಕಡಿಮೆ ಇರಬಹುದು

5. ಡೆಡ್‌ಲಾಕ್ (Deadlock) ಎಂದರೇನು?

ಉತ್ತರ: ಡೆಡ್‌ಲಾಕ್ ಎನ್ನುವುದು ಎರಡು ಅಥವಾ ಅದಕ್ಕಿಂತ ಹೆಚ್ಚು ಥ್ರೆಡ್‌ಗಳು ಪರಸ್ಪರ ಹಿಡಿದಿಟ್ಟುಕೊಂಡಿರುವ ರಿಸೋರ್ಸ್‌ಗಳಿಗಾಗಿ ಕಾಯುತ್ತಾ, ಶಾಶ್ವತವಾಗಿ ಬ್ಲಾಕ್ ಆಗುವ ಒಂದು ಸ್ಥಿತಿ.

ಉದಾಹರಣೆ:

  • ಥ್ರೆಡ್ A, ರಿಸೋರ್ಸ್ 1 ಅನ್ನು ಲಾಕ್ ಮಾಡಿ, ರಿಸೋರ್ಸ್ 2 ಕ್ಕಾಗಿ ಕಾಯುತ್ತಿದೆ.
  • ಥ್ರೆಡ್ B, ರಿಸೋರ್ಸ್ 2 ಅನ್ನು ಲಾಕ್ ಮಾಡಿ, ರಿಸೋರ್ಸ್ 1 ಕ್ಕಾಗಿ ಕಾಯುತ್ತಿದೆ.

ಈ ಸ್ಥಿತಿಯಲ್ಲಿ, ಎರಡೂ ಥ್ರೆಡ್‌ಗಳು ಮುಂದುವರಿಯಲು ಸಾಧ್ಯವಿಲ್ಲ. ಡೆಡ್‌ಲಾಕ್‌ಗಳನ್ನು ತಪ್ಪಿಸಲು ಲಾಕಿಂಗ್ ಕ್ರಮವನ್ನು ಎಚ್ಚರಿಕೆಯಿಂದ ವಿನ್ಯಾಸಗೊಳಿಸಬೇಕು (ಉದಾ: ಎಲ್ಲಾ ಥ್ರೆಡ್‌ಗಳು ಒಂದೇ ಕ್ರಮದಲ್ಲಿ ಲಾಕ್‌ಗಳನ್ನು ಪಡೆಯುವುದು).