เริ่มจากการ import library multiprocessing มาก่อนโดยส่วนที่จะใช้คือ
จากนั้นทำการสร้างฟังค์ชันที่ใช้สำหรับทดสอบ โดยจะแบ่งเป็น 2 ฟังค์ชันคือ
1. ฟังค์ชันที่ใช้ sleep เพื่อหน่วงเวลาการทำงาน 1 วินาที
2. ฟังค์ชั้น loop ทั่วไป โดยภายใน loop จะเพิ่มค่าที 1 จนกว่าจะถึงเงื่อนไขที่ตั้งไว้ในการหน่วงเวลาแทนการใช้ time.sleep
โดยวิธีการเรียกใช้จะแบ่งเป็น 2 วิธี คือ
1. การเรียกใช้ฟังค์ชันแบบเป็นลำดับ โดย NUM_WORKERS จะเก็บจำนวน core ของ cpu มาใช้ ในที่นี้คือ 8 cores
2. การเรียกใช้ฟังค์ชันแบบ Multiprocessing
โดยฟังค์ชันของ Multiprocessing นั้นจะแบ่งเป็นหลักๆคือ
จากภาพผลการทำงานแบบลำดับนั้นจะใช้เวลา 8 วินาที แต่การทำงานแบบ Multiprocessing จะใช้เวลาเพียง 1 วินาที เนื่องจากทั้ง 8 processes นั้นทำงานในเวลา
* ข้อสังเกต : process นั้นมีความเป็นไปได้ที่จะมีตัวใดตัวหนึ่งทำงานเสร็จก่อน จึงทำให้ลำดับการทำงานไม่ออกมาตรงตามที่เราต้องการเสมอไป ดังรูปจะสังเกตได้ว่า process 6 ทำงานเสร็จก่อน process 5 เป็นต้น
การทดลองในส่วนถัดไปจะใช้ฟังค์ชัน crunch_number แทน only_sleep ได้ผลดังนี้
from multiprocessing import Process, current_process, cpu_count
import threading
import os
import time
from timeit import default_timer as timer
import threading
import os
import time
from timeit import default_timer as timer
- Process สำหรับสร้าง process
- current_process สำหรับแสดงชื่อของ process ที่ทำงานอยู่ขณะนั้น
- cpu_count สำหรับเก็บจำนวน core ของ CPU ซึ่งในที่นี้จะทำการรันฟังค์ชัน ตามจำนวนของ core ที่มี
- threading สำหรับตรวจสอบชื่อของ thread ที่ทำงานขณะนั้น
- os สำหรับตรวจสอบ pid ที่ทำงานขณะนั้น
- timeit สำหรับจับเวลาการทำงานของฟังค์ชันหรือ process
- time สำหรับใช้หน่วงเวลาการทำงานของฟังค์ชันโดยใช้ time.sleep
จากนั้นทำการสร้างฟังค์ชันที่ใช้สำหรับทดสอบ โดยจะแบ่งเป็น 2 ฟังค์ชันคือ
1. ฟังค์ชันที่ใช้ sleep เพื่อหน่วงเวลาการทำงาน 1 วินาที
def only_sleep():
# Do nothing, wait for a timer to expire
print("PID: %s, Process Name: %s, Thread Name: %s" % (
os.getpid(),
current_process().name,
threading.current_thread().name))
time.sleep(1)
# Do nothing, wait for a timer to expire
print("PID: %s, Process Name: %s, Thread Name: %s" % (
os.getpid(),
current_process().name,
threading.current_thread().name))
time.sleep(1)
2. ฟังค์ชั้น loop ทั่วไป โดยภายใน loop จะเพิ่มค่าที 1 จนกว่าจะถึงเงื่อนไขที่ตั้งไว้ในการหน่วงเวลาแทนการใช้ time.sleep
def crunch_numbers():
# Do some computations
print("PID: %s, Process Name: %s, Thread Name: %s" % ( os.getpid(),current_process().name,threading.current_thread().name))
x = 0
while x < 10000000:
x += 1
# Do some computations
print("PID: %s, Process Name: %s, Thread Name: %s" % ( os.getpid(),current_process().name,threading.current_thread().name))
x = 0
while x < 10000000:
x += 1
โดยวิธีการเรียกใช้จะแบ่งเป็น 2 วิธี คือ
1. การเรียกใช้ฟังค์ชันแบบเป็นลำดับ โดย NUM_WORKERS จะเก็บจำนวน core ของ cpu มาใช้ ในที่นี้คือ 8 cores
if __name__ == "__main__":
NUM_WORKERS = cpu_count()
# Run tasks serially
start_time = timer()
for _ in range(NUM_WORKERS):
only_sleep()
end_time = timer()
print("Serial time = %s" %(end_time - start_time))
NUM_WORKERS = cpu_count()
# Run tasks serially
start_time = timer()
for _ in range(NUM_WORKERS):
only_sleep()
end_time = timer()
print("Serial time = %s" %(end_time - start_time))
2. การเรียกใช้ฟังค์ชันแบบ Multiprocessing
# Run tasks using processes
start_time = timer()
processes = [Process(target=only_sleep) for _ in range(NUM_WORKERS)]
[process.start() for process in processes]
[process.join() for process in processes]
end_time = timer()
print("Parallel time = %s" %(end_time - start_time))
start_time = timer()
processes = [Process(target=only_sleep) for _ in range(NUM_WORKERS)]
[process.start() for process in processes]
[process.join() for process in processes]
end_time = timer()
print("Parallel time = %s" %(end_time - start_time))
โดยฟังค์ชันของ Multiprocessing นั้นจะแบ่งเป็นหลักๆคือ
- Process ใช้สำหรับสร้าง process โดยภายในจะมีตัวแปรหลักๆ 2 ตัวคือ
- target สำหรับใส่ฟังค์ชันที่เราต้องการให้ process ใช้ทำงาน
- args สำหรับป้อนตัวแปรที่จะส่งเข้าไปให้ฟังค์ชันใน target ทำงาน หากไม่มีตัวแปรที่ต้องส่งสามารถใช้ args=() หรือ ไม่ใส่ก็ได้
- start() ใช้สั่งให้ process นั้นๆทำงาน
- join() ใช้สำหรับบังคับให้รอจนกว่า process ตัวที่ทำงานอยู่นั้นเสร็จสิ้นก่อน จึงจะทำงานอื่นต่อไป
จากภาพผลการทำงานแบบลำดับนั้นจะใช้เวลา 8 วินาที แต่การทำงานแบบ Multiprocessing จะใช้เวลาเพียง 1 วินาที เนื่องจากทั้ง 8 processes นั้นทำงานในเวลา
* ข้อสังเกต : process นั้นมีความเป็นไปได้ที่จะมีตัวใดตัวหนึ่งทำงานเสร็จก่อน จึงทำให้ลำดับการทำงานไม่ออกมาตรงตามที่เราต้องการเสมอไป ดังรูปจะสังเกตได้ว่า process 6 ทำงานเสร็จก่อน process 5 เป็นต้น
การทดลองในส่วนถัดไปจะใช้ฟังค์ชัน crunch_number แทน only_sleep ได้ผลดังนี้
จากภาพเวลาการทำงานแบบลำดับนั้นคือ 2.8 วินาที และเวลาการทำงานแบบ Multiprocessing นั้นใช้เวลาการทำงานเพียง 0.7 วินาที ซึ่งเป็น 1/4 ของเวลาที่ใช้ไปในแบบลำดับ
** ข้อสังเกต : เพื่อให้เห็นภาพที่ชัดเจนเกี่ยวกับ Multiprocess มากขึ้น จึงได้ทำการปรับโค้ด crunch_number จากให้ค่าของ loop เพิ่มทีละ 1 เป็น 0.1
def crunch_numbers():
# Do some computations
print("PID: %s, Process Name: %s, Thread Name: %s" % (
os.getpid(),
current_process().name,
threading.current_thread().name))
x = 0
while x < 10000000:
# x += 1
x += 0.1
# Do some computations
print("PID: %s, Process Name: %s, Thread Name: %s" % (
os.getpid(),
current_process().name,
threading.current_thread().name))
x = 0
while x < 10000000:
# x += 1
x += 0.1
ซึ่งจะได้ผลตามภาพดังนี้
ภาพการทำงานของ CPU core ช่วงการทำงานแบบลำดับ
ภาพการทำงานของ CPU core ช่วงการทำงานแบบ Multiprocessing
จะพบว่าในช่วงการทำงานของ Multiprocessing นั้น CPU core จะทำงานพร้อมกันทั้ง 8 cores ซึ่งต่างจากการทำงานแบบลำดับที่การประมวลผลทั้งหมดจะทำงานอยู่ที่ 1 core เท่านั้น




ไม่มีความคิดเห็น:
แสดงความคิดเห็น