ಪೈಥಾನ್ ಮಲ್ಟಿಪ್ರೊಸೆಸಿಂಗ್: ಸಂದರ್ಶನ ಪ್ರಶ್ನೆಗಳು
1. ಮಲ್ಟಿಪ್ರೊಸೆಸಿಂಗ್ (Multiprocessing) ಎಂದರೇನು?
ಉತ್ತರ: ಮಲ್ಟಿಪ್ರೊಸೆಸಿಂಗ್ ಎನ್ನುವುದು ಹಲವಾರು ಪ್ರೊಸೆಸ್ಗಳನ್ನು (ಪ್ರೋಗ್ರಾಂನ ಸ್ವತಂತ್ರ ಇನ್ಸ್ಟೆನ್ಸ್ಗಳು) ಏಕಕಾಲದಲ್ಲಿ (in parallel) ರನ್ ಮಾಡಲು ಸಿಸ್ಟಮ್ನ ಸಾಮರ್ಥ್ಯ. ಪ್ರತಿ ಪ್ರೊಸೆಸ್ಗೆ ತನ್ನದೇ ಆದ ಮೆಮೊರಿ ಸ್ಪೇಸ್ ಮತ್ತು ಪೈಥಾನ್ ಇಂಟರ್ಪ್ರಿಟರ್ ಇರುತ್ತದೆ.
ಉಪಯೋಗ:
- CPU-ಬೌಂಡ್ ಟಾಸ್ಕ್ಗಳಿಗೆ: ಗಣಿತದ ಲೆಕ್ಕಾಚಾರಗಳು, ಡೇಟಾ ಪ್ರೊಸೆಸಿಂಗ್, ಮತ್ತು ಇಮೇಜ್ ಪ್ರೊಸೆಸಿಂಗ್ನಂತಹ CPU-ತೀವ್ರವಾದ ಕೆಲಸಗಳನ್ನು ನಿಜವಾದ ಪ್ಯಾರಲಲಿಸಂ ಮೂಲಕ ವೇಗಗೊಳಿಸಲು ಇದು ಅತ್ಯಂತ ಪರಿಣಾಮಕಾರಿ. ಇದು GIL (Global Interpreter Lock) ನ ಮಿತಿಯನ್ನು ನಿವಾರಿಸುತ್ತದೆ.
2. ಮಲ್ಟಿಥ್ರೆಡಿಂಗ್ ಮತ್ತು ಮಲ್ಟಿಪ್ರೊಸೆಸಿಂಗ್ ನಡುವೆ ಯಾವಾಗ ಯಾವುದನ್ನು ಆರಿಸಬೇಕು?
ಉತ್ತರ: ಆಯ್ಕೆಯು ನೀವು ಪರಿಹರಿಸಲು ಪ್ರಯತ್ನಿಸುತ್ತಿರುವ ಸಮಸ್ಯೆಯ ಸ್ವರೂಪವನ್ನು ಅವಲಂಬಿಸಿರುತ್ತದೆ:
-
ಮಲ್ಟಿಥ್ರೆಡಿಂಗ್ ಬಳಸಿ:
- I/O-ಬೌಂಡ್ ಟಾಸ್ಕ್ಗಳಿಗಾಗಿ (ಉದಾ: ವೆಬ್ ಸ್ಕ್ರೇಪಿಂಗ್, ಫೈಲ್ ಡೌನ್ಲೋಡ್, ಡೇಟಾಬೇಸ್ ಕಾರ್ಯಾಚರಣೆಗಳು).
- ಇಲ್ಲಿ, ಪ್ರೋಗ್ರಾಂ ಹೆಚ್ಚಾಗಿ ಡೇಟಾಕ್ಕಾಗಿ ಕಾಯುತ್ತಿರುತ್ತದೆ. ಒಂದು ಥ್ರೆಡ್ ಕಾಯುತ್ತಿರುವಾಗ, ಇನ್ನೊಂದು ಥ್ರೆಡ್ ರನ್ ಆಗಬಹುದು.
- ಥ್ರೆಡ್ಗಳು ಮೆಮೊರಿ ಹಂಚಿಕೊಳ್ಳುವುದರಿಂದ, ಅವುಗಳ ನಡುವೆ ಡೇಟಾ ಶೇರಿಂಗ್ ಸುಲಭ.
-
ಮಲ್ಟಿಪ್ರೊಸೆಸಿಂಗ್ ಬಳಸಿ:
- CPU-ಬೌಂಡ್ ಟಾಸ್ಕ್ಗಳಿಗಾಗಿ (ಉದಾ: ವೈಜ್ಞಾನಿಕ ಲೆಕ್ಕಾಚಾರಗಳು, ವಿಡಿಯೋ ಎನ್ಕೋಡಿಂಗ್, ದೊಡ್ಡ ಡೇಟಾಸೆಟ್ಗಳ ವಿಶ್ಲೇಷಣೆ).
- ಇಲ್ಲಿ, ಪ್ರೋಗ್ರಾಂ ನಿರಂತರವಾಗಿ CPU ಅನ್ನು ಬಳಸುತ್ತದೆ. ಮಲ್ಟಿಪ್ರೊಸೆಸಿಂಗ್ GIL ಅನ್ನು ಬೈಪಾಸ್ ಮಾಡಿ, ನಿಜವಾದ ಪ್ಯಾರಲಲಿಸಂ ಅನ್ನು ಸಾಧಿಸಲು ಪ್ರತಿ ಕೋರ್ನಲ್ಲಿ ಪ್ರತ್ಯೇಕ ಪ್ರೊಸೆಸ್ ಅನ್ನು ರನ್ ಮಾಡುತ್ತದೆ.
3. ಪೈಥಾನ್ನಲ್ಲಿ multiprocessing ಮಾಡ್ಯೂಲ್ ಅನ್ನು ಹೇಗೆ ಬಳಸುವುದು?
ಉತ್ತರ:
multiprocessing ಮಾಡ್ಯೂಲ್ threading ಮಾಡ್ಯೂಲ್ಗೆ ಹೋಲುವ API ಅನ್ನು ಒದಗಿಸುತ್ತದೆ. Process ಕ್ಲಾಸ್ ಬಳಸಿ ಹೊಸ
ಪ್ರೊಸೆಸ್ಗಳನ್ನು ರಚಿಸಬಹುದು.
ಉದಾಹರಣೆ:
import multiprocessing
import os
def worker_function(name):
"""ಪ್ರೊಸೆಸ್ನಲ್ಲಿ ರನ್ ಆಗುವ ಫಂಕ್ಷನ್"""
print(f"Worker {name} starting, Process ID: {os.getpid()}")
# CPU-ಬೌಂಡ್ ಕೆಲಸ
total = sum(i for i in range(10 ** 7))
print(f"Worker {name} finished.")
if __name__ == "__main__":
# ಪ್ರೊಸೆಸ್ಗಳನ್ನು ರಚಿಸುವುದು
p1 = multiprocessing.Process(target=worker_function, args=("A",))
p2 = multiprocessing.Process(target=worker_function, args=("B",))
# ಪ್ರೊಸೆಸ್ಗಳನ್ನು ಪ್ರಾರಂಭಿಸುವುದು
p1.start()
p2.start()
# ಪ್ರೊಸೆಸ್ಗಳು ಮುಗಿಯುವವರೆಗೆ ಕಾಯುವುದು
p1.join()
p2.join()
print("All processes finished.")
ಗಮನಿಸಿ: if __name__ == "__main__": ಬ್ಲಾಕ್ ಮಲ್ಟಿಪ್ರೊಸೆಸಿಂಗ್ನಲ್ಲಿ ಕಡ್ಡಾಯವಾಗಿದೆ. ಇದು ಚೈಲ್ಡ್ ಪ್ರೊಸೆಸ್ಗಳು ಮತ್ತೆ
ಸ್ಕ್ರಿಪ್ಟ್ ಅನ್ನು ಇಂಪೋರ್ಟ್ ಮಾಡಿ, ಅನಂತವಾಗಿ ಪ್ರೊಸೆಸ್ಗಳನ್ನು ರಚಿಸುವುದನ್ನು ತಡೆಯುತ್ತದೆ.
4. ಪ್ರೊಸೆಸ್ಗಳ ನಡುವೆ ಡೇಟಾವನ್ನು ಹೇಗೆ ಸಂವಹನ ಮಾಡುವುದು (Inter-Process Communication - IPC)?
ಉತ್ತರ:
ಪ್ರೊಸೆಸ್ಗಳು ಮೆಮೊರಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳುವುದಿಲ್ಲವಾದ್ದರಿಂದ, ಅವುಗಳ ನಡುವೆ ಡೇಟಾ ಸಂವಹನ ಮಾಡಲು ವಿಶೇಷ ಮೆಕ್ಯಾನಿಸಂಗಳು ಬೇಕು.
multiprocessing ಮಾಡ್ಯೂಲ್ ಹಲವಾರು IPC ವಿಧಾನಗಳನ್ನು ಒದಗಿಸುತ್ತದೆ:
-
ಕ್ಯೂ (Queue):
- ಇದು ಒಂದು ಫಸ್ಟ್-ಇನ್, ಫಸ್ಟ್-ಔಟ್ (FIFO) ಡೇಟಾ ಸ್ಟ್ರಕ್ಚರ್.
- ಒಂದು ಪ್ರೊಸೆಸ್
put()ಬಳಸಿ ಡೇಟಾವನ್ನು ಕ್ಯೂಗೆ ಹಾಕಬಹುದು, ಮತ್ತು ಇನ್ನೊಂದು ಪ್ರೊಸೆಸ್get()ಬಳಸಿ ಅದನ್ನು ಪಡೆಯಬಹುದು. - ಇದು ಪ್ರೊಸೆಸ್-ಸೇಫ್ ಆಗಿದೆ, ಅಂದರೆ ಲಾಕ್ಗಳ ಬಗ್ಗೆ ಚಿಂತಿಸಬೇಕಾಗಿಲ್ಲ.
-
ಪೈಪ್ (Pipe):
- ಇದು ಎರಡು ಪ್ರೊಸೆಸ್ಗಳ ನಡುವೆ ನೇರ ಸಂಪರ್ಕವನ್ನು ಸ್ಥಾಪಿಸುತ್ತದೆ.
Pipe()ಫಂಕ್ಷನ್ ಎರಡು ಕನೆಕ್ಷನ್ ಆಬ್ಜೆಕ್ಟ್ಗಳನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತದೆ (ಒಂದು ಕಳುಹಿಸಲು, ಇನ್ನೊಂದು ಸ್ವೀಕರಿಸಲು).- ಕ್ಯೂ ಗಿಂತ ವೇಗವಾಗಿರುತ್ತದೆ, ಆದರೆ ಕೇವಲ ಎರಡು ಪ್ರೊಸೆಸ್ಗಳ ನಡುವೆ ಮಾತ್ರ ಕೆಲಸ ಮಾಡುತ್ತದೆ.
-
ಶೇರ್ಡ್ ಮೆಮೊರಿ (Shared Memory):
Valueಮತ್ತುArrayಬಳಸಿ ಪ್ರೊಸೆಸ್ಗಳ ನಡುವೆ ನೇರವಾಗಿ ಮೆಮೊರಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳಬಹುದು.- ಇದು ಅತ್ಯಂತ ವೇಗವಾಗಿರುತ್ತದೆ, ಆದರೆ ರೇಸ್ ಕಂಡೀಶನ್ಗಳನ್ನು ತಪ್ಪಿಸಲು ಲಾಕ್ಗಳನ್ನು ಬಳಸಿ ಸಿಂಕ್ರೊನೈಸ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ.
5. ಪೂಲ್ ಆಫ್ ವರ್ಕರ್ಸ್ (Pool) ಎಂದರೇನು?
ಉತ್ತರ:
multiprocessing.Pool ಕ್ಲಾಸ್ ವರ್ಕರ್ ಪ್ರೊಸೆಸ್ಗಳ ಒಂದು ಪೂಲ್ ಅನ್ನು ನಿರ್ವಹಿಸಲು ಸುಲಭವಾದ ಮಾರ್ಗವನ್ನು ಒದಗಿಸುತ್ತದೆ. ನೀವು
ನಿರ್ದಿಷ್ಟ ಸಂಖ್ಯೆಯ ಪ್ರೊಸೆಸ್ಗಳನ್ನು ರಚಿಸಿ, ಅವುಗಳಿಗೆ ಕೆಲಸಗಳನ್ನು ಹಂಚಬಹುದು.
ಪ್ರಯೋಜನಗಳು:
- ಪ್ರೊಸೆಸ್ಗಳನ್ನು ಹಸ್ತಚಾಲಿತವಾಗಿ ರಚಿಸುವ ಮತ್ತು ನಿರ್ವಹಿಸುವ ಬದಲು, ಪೂಲ್ ಅದನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಮಾಡುತ್ತದೆ.
- ಸಿಸ್ಟಮ್ನ ಕೋರ್ಗಳ ಸಂಖ್ಯೆಗೆ ಅನುಗುಣವಾಗಿ ಪ್ರೊಸೆಸ್ಗಳ ಸಂಖ್ಯೆಯನ್ನು ಸುಲಭವಾಗಿ ಮಿತಿಗೊಳಿಸಬಹುದು.
ಉದಾಹರಣೆ:
import multiprocessing
def square(n):
return n * n
if __name__ == "__main__":
numbers = [1, 2, 3, 4, 5]
# CPU ಕೋರ್ಗಳ ಸಂಖ್ಯೆಯಷ್ಟು ಪ್ರೊಸೆಸ್ಗಳ ಪೂಲ್ ರಚಿಸುತ್ತದೆ
with multiprocessing.Pool() as pool:
# 'map' ಫಂಕ್ಷನ್ 'numbers' ಲಿಸ್ಟ್ನ ಪ್ರತಿಯೊಂದು ಐಟಂ ಅನ್ನು 'square' ಫಂಕ್ಷನ್ಗೆ ಕಳುಹಿಸುತ್ತದೆ
results = pool.map(square, numbers)
print(results) # [1, 4, 9, 16, 25]