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

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

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 ವಿಧಾನಗಳನ್ನು ಒದಗಿಸುತ್ತದೆ:

  1. ಕ್ಯೂ (Queue):

    • ಇದು ಒಂದು ಫಸ್ಟ್-ಇನ್, ಫಸ್ಟ್-ಔಟ್ (FIFO) ಡೇಟಾ ಸ್ಟ್ರಕ್ಚರ್.
    • ಒಂದು ಪ್ರೊಸೆಸ್ put() ಬಳಸಿ ಡೇಟಾವನ್ನು ಕ್ಯೂಗೆ ಹಾಕಬಹುದು, ಮತ್ತು ಇನ್ನೊಂದು ಪ್ರೊಸೆಸ್ get() ಬಳಸಿ ಅದನ್ನು ಪಡೆಯಬಹುದು.
    • ಇದು ಪ್ರೊಸೆಸ್-ಸೇಫ್ ಆಗಿದೆ, ಅಂದರೆ ಲಾಕ್‌ಗಳ ಬಗ್ಗೆ ಚಿಂತಿಸಬೇಕಾಗಿಲ್ಲ.
  2. ಪೈಪ್ (Pipe):

    • ಇದು ಎರಡು ಪ್ರೊಸೆಸ್‌ಗಳ ನಡುವೆ ನೇರ ಸಂಪರ್ಕವನ್ನು ಸ್ಥಾಪಿಸುತ್ತದೆ.
    • Pipe() ಫಂಕ್ಷನ್ ಎರಡು ಕನೆಕ್ಷನ್ ಆಬ್ಜೆಕ್ಟ್‌ಗಳನ್ನು ಹಿಂತಿರುಗಿಸುತ್ತದೆ (ಒಂದು ಕಳುಹಿಸಲು, ಇನ್ನೊಂದು ಸ್ವೀಕರಿಸಲು).
    • ಕ್ಯೂ ಗಿಂತ ವೇಗವಾಗಿರುತ್ತದೆ, ಆದರೆ ಕೇವಲ ಎರಡು ಪ್ರೊಸೆಸ್‌ಗಳ ನಡುವೆ ಮಾತ್ರ ಕೆಲಸ ಮಾಡುತ್ತದೆ.
  3. ಶೇರ್ಡ್ ಮೆಮೊರಿ (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]