آموزش پردازش چندگانه در همزمانی در پایتون 

3 سال پیش
آموزش پردازش چندگانه در همزمانی در پایتون

آموزش پردازش چندگانه در همزمانی در پایتون 

 

در این درس از مجموعه آموزش برنامه نویسی سایت سورس باران، به آموزش پردازش چندگانه در همزمانی در پایتون خواهیم پرداخت.

پیشنهاد ویژه : پکیج آموزش پروژه محور پایتون

در این درس، ما بیشتر به مقایسه بین پردازش چندگانه  و چند رشته خواهیم پرداخت.

پردازش چندگانه در همزمانی در پایتون

این استفاده از دو یا چند واحد پردازنده در یک سیستم رایانه ای است. این بهترین روش برای به دست آوردن پتانسیل کامل از سخت افزارهای ما با استفاده از تعداد کامل هسته های پردازنده موجود در سیستم رایانه ای ما است.

چند رشته ای

این توانایی CPU است که می تواند با استفاده از چندین رشته همزمان، استفاده از سیستم عامل را مدیریت کند. ایده اصلی چند رشته ای دستیابی به موازی کاری با تقسیم یک فرآیند به چندین رشته است.

جدول زیر برخی از تفاوتهای مهم بین آنها را نشان می دهد –

پردازش چندگانه چند برنامه ای
پردازش چندگانه به پردازش همزمان چندین پردازش توسط چندین پردازنده مرکزی اشاره دارد. چند برنامه ریزی همزمان چندین برنامه را در حافظه اصلی نگه داشته و همزمان با استفاده از تک پردازنده آنها را اجرا می کند.
از چند پردازنده استفاده می کند. از تک پردازنده استفاده می کند.
 اجازه پردازش موازی را می دهد. تغییر متن انجام می شود.
برای پردازش وقت کمتری صرف می کند زمان بیشتری برای پردازش صرف می کند
استفاده بسیار کارآمد از دستگاه های سیستم رایانه ای را تسهیل می کند. کارآیی کمتر از پردازش چندگانه دارد.
معمولا گران تر است هزینه کمتری را شامل می شود

از بین بردن تأثیر GIL

هنگام کار با برنامه های همزمان، محدودیتی در پایتون وجود دارد که GIL (Global Interpreter Lock) نامیده می شود. GIL هرگز به ما اجازه استفاده از چندین هسته پردازنده را نمی دهد و از این رو می توان گفت که هیچ رشته واقعی در پایتون وجود ندارد. GIL mutex است – قفل محرومیت متقابل ، که باعث می شود همه چیز ایمن باشد. به عبارت دیگر، می توان گفت که GIL از اجرای چندین رشته به طور موازی کد پایتون جلوگیری می کند. قفل را می توان همزمان فقط با یک رشته نگه داشت و اگر بخواهیم یک رشته را اجرا کنیم ، ابتدا باید قفل را بدست آورد.

با استفاده از پردازش چندگانه، ما می توانیم به طور موثر محدودیت ناشی از GIL را کنار بگذاریم –

با استفاده از پردازش چندگانه، ما از قابلیت چندین فرآیند استفاده می کنیم و بنابراین از چندین نمونه GIL استفاده می کنیم.

به همین دلیل، هیچ محدودیتی در اجرای بایت کد یک رشته در برنامه های ما در هر زمان وجود ندارد.

 

شروع پردازش ها در پایتون

از سه روش زیر می توان برای شروع فرآیند در پایتون در ماژول چند پردازش استفاده کرد –

  • Fork
  • Spawn
  • Forkserver

ایجاد یک پردازش با Fork

دستور Fork یک دستور استاندارد است که در UNIX یافت می شود. برای ایجاد فرایندهای جدید به نام فرآیندهای کودک استفاده می شود. این فرآیند کودک همزمان با فرآیندی موسوم به فرآیند والد اجرا می شود. این فرایندهای کودک نیز با فرایندهای والد آنها یکسان است و تمام منابع موجود در اختیار والد را به ارث می برد. هنگام ایجاد فرایند با Fork، از فراخوانی های سیستمی زیر استفاده می شود –

  • ()fork- این یک فراخوان سیستمی است که به طور کلی در هسته اجرا می شود. برای ایجاد کپی از روند استفاده می شود. p>
  • ()getpid- این تماس سیستم شناسه فرآیند (PID) فرآیند فراخوانی را برمی گرداند.

مثال

مثال زیر در اسکریپت پایتون به شما کمک می کند تا چگونگی ایجاد یک فرآیند کودک جدید و دریافت PID های فرآیندهای کودک و والد را کم کنید.

import os

def child():
   n = os.fork()
   
   if n > 0:
      print("PID of Parent process is : ", os.getpid())

   else:
      print("PID of Child process is : ", os.getpid())
child()

 

خروجی

PID of Parent process is : 25989
PID of Child process is : 25990

 

ایجاد یک پردازش با Spawn

Spawn یعنی شروع کار جدید. از این رو Spawn یک فرآیند به معنای ایجاد فرایند جدید توسط یک فرآیند والد است. فرآیند والد به طور همزمان به اجرای خود ادامه می دهد یا منتظر می ماند تا روند کودک به اجرای خود پایان دهد. برای Spawn یک فرآیند این مراحل را دنبال کنید –

  • وارد کردن ماژول پردازش چند گانه.
  • ایجاد فرایند شی.
  • شروع فعالیت پردازش با فراخوانی متد ()start .
  • منتظر بمانید تا روند کار به پایان برسد و با فراخوانی متد ()join  از آن خارج شوید.

مثال

مثال زیر از اسکریپت پایتون به Spawn کردن سه پردازش کمک می کند

import multiprocessing

def spawn_process(i):
   print ('This is process: %s' %i)
   return

if __name__ == '__main__':
   Process_jobs = []
   for i in range(3):
   p = multiprocessing.Process(target = spawn_process, args = (i,))
      Process_jobs.append(p)
   p.start()
   p.join()

 

خروجی

This is process: 0
This is process: 1
This is process: 2

 

ایجاد یک پردازش با Forkserver

مکانیزم Forkserver فقط در آن سیستم عاملهای انتخاب شده یونیکس موجود است که از عبور توصیفگرهای پرونده از طریق لوله های یونیکس پشتیبانی می کنند. برای درک عملکرد مکانیسم Forkserver ، نکات زیر را در نظر بگیرید –

  • یک سرور برای استفاده از مکانیزم Forkserver برای شروع پردازش جدید استفاده می شود.
  • سپس سرور فرمان را دریافت می کند و کلیه درخواست های ایجاد پردازش های جدید را کنترل می کند.
  • برای ایجاد یک روند جدید، برنامه پایتون ما درخواستی را به Forkserver ارسال می کند و پردازشی را برای ما ایجاد می کند.
  • سرانجام، ما می توانیم از این روند ایجاد شده جدید در برنامه های خود استفاده کنیم.

 

پردازش های Daemon در پایتون

ماژول چند پردازشی پایتون به ما امکان می دهد فرآیندهای Daemon را از طریق گزینه daemonic خود داشته باشیم. فرآیندهای Daemon یا فرایندهایی که در پس زمینه اجرا می شوند از مفهوم مشابه رشته های Daemon پیروی می کنند. برای اجرای پردازش در پس زمینه، باید پرچم daemonic را روی true تنظیم کنیم. روند daemon تا زمانی که فرآیند اصلی در حال اجرا است ادامه خواهد داشت و پس از اتمام اجرای آن یا زمانی که برنامه اصلی از بین می رود ، خاتمه می یابد.

مثال

در اینجا، ما از همان مثالی استفاده می کنیم که در رشته های Daemon استفاده شده است. تنها تفاوت تغییر ماژول از چند رشته به چند پردازش و تنظیم پرچم daemonic به true است. با این حال، تغییر در خروجی همانطور که در زیر نشان داده شده است، وجود دارد

import multiprocessing
import time

def nondaemonProcess():
   print("starting my Process")
   time.sleep(8)
   print("ending my Process")
def daemonProcess():
   while True:
   print("Hello")
   time.sleep(2)
if __name__ == '__main__':
   nondaemonProcess = multiprocessing.Process(target = nondaemonProcess)
   daemonProcess = multiprocessing.Process(target = daemonProcess)
   daemonProcess.daemon = True
   nondaemonProcess.daemon = False
   daemonProcess.start()
   nondaemonProcess.start()

 

خروجی

starting my Process
ending my Process

 

خروجی در مقایسه با خروجی تولید شده توسط رشته های Daemon متفاوت است، زیرا پردازش در هیچ حالت Daemon خروجی ندارد. از این رو، پردازش daemonic به طور خودکار پس از پایان برنامه های اصلی به منظور جلوگیری از پایداری فرآیندهای در حال اجرا به پایان می رسد.

فرایندهای خاتمه در پایتون

ما می توانیم بلافاصله با استفاده از متد ()terminate  فرایندی را از بین ببریم یا خاتمه دهیم. ما از این روش برای خاتمه فرایند کودک، که با کمک تابع ایجاد شده است ، بلافاصله قبل از اتمام اجرای آن استفاده خواهیم کرد.

مثال

import multiprocessing
import time
def Child_process():
   print ('Starting function')
   time.sleep(5)
   print ('Finished function')
P = multiprocessing.Process(target = Child_process)
P.start()
print("My Process has terminated, terminating main thread")
print("Terminating Child Process")
P.terminate()
print("Child Process successfully terminated")

 

خروجی

 

My Process has terminated, terminating main thread
Terminating Child Process
Child Process successfully terminated

 

خروجی نشان می دهد که برنامه قبل از اجرای فرآیند کودک که با کمک تابع ()Child_process  ایجاد شده است ، خاتمه می یابد. این بدان معنی است که فرایند کودک با موفقیت خاتمه یافته است.

 

شناسایی فرایند فعلی در پایتون

هر فرآیند در سیستم عامل دارای هویت فرآیند است که به PID معروف است. در پایتون، با کمک دستور زیر می توانیم PID روند فعلی را پیدا کنیم –

import multiprocessing
print(multiprocessing.current_process().pid)

 

مثال

مثال زیر از اسکریپت پایتون به کشف PID فرایند اصلی و همچنین PID فرایند کودک کمک می کند –

import multiprocessing
import time
def Child_process():
   print("PID of Child Process is: {}".format(multiprocessing.current_process().pid))
print("PID of Main process is: {}".format(multiprocessing.current_process().pid))
P = multiprocessing.Process(target=Child_process)
P.start()
P.join()

 

خروجی

 

PID of Main process is: 9401
PID of Child Process is: 9402

 

استفاده از فرآیند در زیر کلاس

ما می توانیم رشته ها را با زیر طبقه بندی موضوع ایجاد کنیم. کلاس موضوع علاوه بر این ، ما می توانیم با طبقه بندی فرعی کلاس multiprocessing.Process فرآیندهایی نیز ایجاد کنیم. برای استفاده از یک فرآیند در زیر کلاس ، باید نکات زیر را در نظر بگیریم –

  • ما باید زیر کلاس جدیدی از کلاس Process تعریف کنیم.
  • ما باید کلاس _init_ (self [، ​​args]) را نادیده بگیریم.
  • برای پیاده سازی فرآیند، باید روش run (self [، ​​args]) را نادیده بگیریم
  • ما باید فرآیند را با فراخوانی روش()thestart شروع کنیم.

مثال

import multiprocessing
class MyProcess(multiprocessing.Process):
   def run(self):
   print ('called run method in process: %s' %self.name)
   return
if __name__ == '__main__':
   jobs = []
   for i in range(5):
   P = MyProcess()
   jobs.append(P)
   P.start()
   P.join()

 

خروجی

called run method in process: MyProcess-1
called run method in process: MyProcess-2
called run method in process: MyProcess-3
called run method in process: MyProcess-4
called run method in process: MyProcess-5

 

ماژول پردازش چندگانه پایتون
اگر ما در مورد برنامه های پردازش موازی ساده در برنامه های پایتون صحبت کنیم، ماژول پردازش چندگانه کلاس Pool را برای ما فراهم می کند. برای چرخش تعداد فرآیندهای کودک در برنامه اصلی ما می توان از روشهای زیر کلاس Pool استفاده کرد

روش ()apply

این روش مشابه ()submit  در روش ThreadPoolExecutor است. تا آماده شدن نتیجه مسدود می شود.

روش ()apply_async 

هنگامی که به اجرای موازی وظایف خود نیاز داریم ، پس باید از روش ()apply_async برای ارسال وظایف به مجموعه استفاده کنیم. این یک عملیات ناهمزمان است که تا زمانی که تمام فرایندهای کودک اجرا نشوند ، رشته اصلی را قفل نمی کند.

روش ()map

درست مانند روش ()apply، تا آماده شدن نتیجه نیز مسدود می شود. این معادل تابع () map داخلی است که داده های قابل تکرار را در چند قسمت تقسیم کرده و به عنوان کارهای جداگانه به مجموعه فرآیند ارسال می کند.

 

مثال

مثال زیر به شما کمک می کند یک مجموعه فرآیند برای اجرای موازی اجرا کنید. محاسبه ساده مربع تعداد با استفاده از تابع ()square از طریق روش چند پردازشی انجام شده است. سپس از ()pool.map  برای ارسال ۵ استفاده شده است ، زیرا ورودی لیستی از اعداد صحیح از ۰ تا ۴ است. نتیجه در p_output ها ذخیره می شود و چاپ می شود.

def square(n):
   result = n*n
   return result
if __name__ == '__main__':
   inputs = list(range(5))
   p = multiprocessing.Pool(processes = 4)
   p_outputs = pool.map(function_square, inputs)
   p.close()
   p.join()
   print ('Pool :', p_outputs)

 

خروجی

Pool : [0, 1, 4, 9, 16]

 

منبع.

لیست جلسات قبل آموزش همزبانی در پایتون

  1. آموزش همزمانی در برنامه نویسی پایتون
  2. آموزش همزمانی در برنامه نویسی پایتون _ مقدمه
  3. آموزش معماری سیستم و حافظه در برنامه نویسی پایتون
  4.  آموزش رشته ها در همزمانی پایتون 
  5. آموزش پیاده سازی رشته در همزمانی پایتون
  6. آموزش همگام سازی رشته ها در همزمانی پایتون
  7. آموزش ارتباط رشته ها در همزمانی پایتون
  8. آموزش تست برنامه های رشته در همزمانی پایتون
  9. اشکال زدایی از برنامه های رشته در همزمانی پایتون
  10. آموزش بنچ مارکینگ و پروفایل در همزمانی پایتون
  11. آموزش مجموعه رشته ها در همزمانی در پایتون 
  12.  آموزش مجموعه مراحل در همزمانی در پایتون
0
برچسب ها :
نویسنده مطلب erfan molaei

دیدگاه شما

بدون دیدگاه