ویرگول
ورودثبت نام
امیرحسین ناظوری
امیرحسین ناظوری📕 عاشق یادگیری و به اشتراک‌گذاری دانش -- آیدی من تو شبکه های اجتماعی : mrNazouri13
امیرحسین ناظوری
امیرحسین ناظوری
خواندن ۱۶ دقیقه·۶ ماه پیش

هم‌زمانی، موازی‌سازی و چندنخی در Python به زبان ساده

تو این مقاله موضوعات همزمانی، موازی سازی و چندنخی در Python به زبان ساده و بصورت کامل بررسی میشه.

Concurrency (همزمانی): یعنی مدیریت چند کار در یک زمان ولی نه الزاما با اجرای همزمان.
Parallelism (موازیسازی): یعنی اجرای واقعی چند کار دقیقا در یک لحظه روی process های مختلف.

یه آشپز داری (انگار یه هسته یا یه نخ) اون آشپز بین کارها جابجا میشه:
یه کم غذا میپزه
بعد سریع میره چندتا ظرف میشوره
بعد برمیگرده سر غذا
و اینطوری هی بین کارها سوییچ میکنه
تو فکر میکنی داره همزمان دو تا کار انجام میده، ولی در واقع فقط یکی یکی و سریع داره بینشون عوض میشه. این میشه Concurrency یا همزمانی.

این بار دو تا آشپز جدا داری (انگار دو هسته یا دو نخ دارم)
یکی فقط غذا میپزه
یکی فقط ظرف میشوره
و هر دو واقعا همزمان دارن کار میکنن
این میشه Parallelism یا موازی سازی

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

از طرفی، تو مفهوم موازی سازی، کارها واقعا همزمان دارن انجام میشه! مثل اینکه دوتا آشپز داریم و اینها در واقعیت بصورت همزمان دارن کار میکنن (یکی آشپزی میکنه، یکی هم همزمان مثلا داره هویج خرد میکنه) برای موازی سازی (Parallelism) نمیتونیم از CPU تک هسته استفاده کنیم.

برای درک بهتر این دو موضوع بریم با CPU آشنا بشیم و درآخر یه جمع بندی از گفته های بالا داشته باشیم.
CPU یعنی Central Processing Unit یا همون «واحد پردازش مرکزی». این همون چیزیه که تو همه ی کامپیوترها هست و مثل مغز عمل میکنه و تمام دستورات برنامت رو اجرا میکنه.
هسته (Core) چیه؟ هر CPU از یک یا چند هسته ساخته شده. هر هسته مثل یه مغز کوچیک توی مغز بزرگتره. هر هسته میتونه یه کار جداگانه رو همزمان با بقیه اجرا کنه.
نخ (Thread) چیه؟ بزار با توجه به گفته های بالا توضیح بدم! وقتی من یک آشپز دارم (یک هسته دارم)، اون آشپز یا هسته میاد هرکارش رو داخل یک نخ قرار میده! مثلا اول هویج خرد میکنه، خب اینجا روی نخ هویج زمان گذاشت! بعد سریع میره سراغ قابلمه، خب اینجا روی نخ قابلمه زمان گذاشت و... که درکل یک آشپز یا یک CPU تک هسته خیلی سریع بین نخ ها جا به جا میشه (تو ذهن ما انگار داره همزمان اجرا میشه، ولی در واقع یکی یکی هست، با سرعت زیاد)
حالا اگه قرار باشه تو آشپزخونه چندتا نخ واقعا همزمان اجرا بشن باید چیکار کرد؟ باید یه آشپز دیگه هم اضافه بشه (یه هسته دیگه هم داشته باشیم) تو این حالت هر آشپز یا هر هسته یه نخ رو میتونه همزمان با اون یکی آشپز یا با اون یکی هسته انجام بده. جمع بندی:
نخ یه چیز نرم افزاریه (مثل کار و فکری که تو سر آشپز هست که مثلا بعد خرد کردن هویج باید سریع بره سراغ قابلمه)
هسته یه چیز سخت افزاریه (مثل اینکه دوتا آشپز بصورت فیزیکی وجود داشته باشن)
یه هسته فقط یه نخ رو همزمان میتونه اجرا کنه. اگه چند نخ وجود داشته باشه، هسته سریع بینشون جابجا میشه (مثلاً هر 0.001 ثانیه یک نخ) تا به نظر برسه همزمان اجرا میشن.

به کد زیر دقت کن:

Name = input("Enter Name: ") Age = int(input("Enter Age: ")) print(f"Your information:\nName: {Name}\nAge: {Age}")

این کد یه کد کاملا ساده پایتونیه، وقتی اجرا میشه نه از مدل هم زمانی استفاده میکنه و نه از مدل موازی سازی! چرا؟ چون اصلا نخ اضافی یا هسته دوم یا async تعریف نشده.
(کد ساده پایتون = فقط یک نخ و یک هسته = اجرای خط به خط و سریالی = نه همزمانی نه موازی سازی)


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

import threading def task(): for i in range(1000000): i * i for _ in range(4): t = threading.Thread(target=task) t.start()

اینجا 4 تا نخ ساختی، ولی چون GIL وجود داره فقط یکی از نخ ها در لحظه اجازه اجرا داره.
الان که GIL رو درک کردیم، بپردازیم به 3 روش پیاده سازی همزمانی در پایتون...
1 - Multithreading (چندنخی) چیه؟
threading یعنی بتونی چند کار رو همزمان انجام بدی، با این ترفند که برنامت بینشون هی جابجا بشه. نه اینکه واقعا با چند هسته همزمان اجرا شه (به خاطر GIL).
تصور کن یه نفر داره:
بسته جمع میکنه
آدرس مینویسه
بسته رو پست میکنه
اگه فقط یه نخ باشه، همه این کارها پشت سر هم انجام میشه. ولی با نخ های جدا، این آدم میتونه بین کارها سریع بپره و یه کم از هر کار انجام بده! به نظر میاد همزمانه.
مثال ساده. فرض کن میخوای یه فایل رو دانلود کنی و همزمان یه پیام نشون بدی: (فعلا کار به کدش نداشته باش)

import threading import time def download_file(): print("Start Download...") time.sleep(5) # شبیهسازی دانلود print("Finish Download") def show_message(): print("Please wait...") # ساختن نخها thread1 = threading.Thread(target = download_file) thread2 = threading.Thread(target = show_message) # شروع نخها thread1.start() thread2.start() # صبر کردن تا تموم بشن thread1.join() thread2.join()

این نخ ها واقعا همزمان اجرا نمیشن چون GIL فقط به یکی در آنِ واحد اجازه میده اجرا بشه. اما چون بینشون سریع جابجا میشه، تو فکر میکنی همزمان اجرا میشن (Concurrency). threading برای کارهایی مثل خوندن فایل، دانلود کردن، چک کردن شبکه و... خوبه، چون اونجا CPU خیلی درگیر نیست.
چطوری از threading استفاده کنیم؟
اول از همه لازمه به پروژه اضافه کنیمش:

import threading

چطوری یه نخ (Thread) بسازیم؟ برای ساخت نخ، یه شی از کلاس threading.Thread درست میکنی:

my_thread = threading.Thread(target = my_function)

تحلیل:
threading.Thread: کلاسی که نخ میسازه.
my_function: تابعی که قراره نخ اجراش کنه.
my_thread: شیءیی که نخ توشه. فعلاً ساخته شده ولی هنوز اجرا نشده (وقتی این خط رو مینویسی، نخ ساخته میشه اما هنوز CPU بهش زمان نداده. فقط توی لیست نخ ها آماده شده)
چطوری نخ رو اجرا کنیم؟

my_thread.start()

سیستم عامل نخ رو فعال میکنه و شروع میکنه به اجرای اون تابعی که دادی (my_function) در کنار نخ اصلی برنامه، حالا یه نخ دیگه هم داری که داره جداگانه کار میکنه.
برای اینکه نخ اصلی صبر کنه تا نخ فرعی تموم شه:

my_thread.join()

اینجا به نخ اصلی یا به برنامه فعلی پایتون گفتم هیچ کاری نکن تا این نخ کارش تموم شه.
مثال جامع:

import threading import time def greet(): for i in range(3): print("Hello") time.sleep(1) # ساخت نخ t = threading.Thread(target = greet) # اجرای نخ t.start() # منتظر بمون تا نخ تموم بشه t.join() print("Finish")

تابع greet قراره سه بار Hello بده، هر بار با 1 ثانیه فاصله.
با Thread یه نخ ساختیم که قراره این تابع رو اجرا کنه.
با start نخ واقعا شروع به اجرا کرد.
greet روی نخ جدا اجرا میشه و در همین حین، نخ اصلی میتونه به کارش ادامه بده (اگه join نمیذاشتی).
join باعث شد تا خط آخر (print نهایی) صبر کنه تا greet تموم شه.
من میتونم بدین شکل هم عمل کنم:

import threading import time def Hello(): for i in range(3): print("Hello") time.sleep(1) def Goodby(): for i in range(3): print("Goodby") time.sleep(1) # ساخت نخ ها t = threading.Thread(target = Hello) t2 = threading.Thread(target = Goodby) # اجرای نخ ها t.start() t2.start() # منتظر بمون تا نخ ها تموم بشن t.join() t.join() print("Finish")

خروجی:

Hello Goodby Hello Goodby Hello Goodby Finish

حالا اگه متد join رو برای نخ ها صدا نزنم چی میشه؟! یعنی:

import threading import time def Hello(): for i in range(3): print("Hello") time.sleep(1) def Goodby(): for i in range(3): print("Goodby") time.sleep(1) # ساخت نخ ها t = threading.Thread(target = Hello) t2 = threading.Thread(target = Goodby) # اجرای نخ ها t.start() t2.start() print("Finish")

خروجی:

Hello Goodby Finish Goodby Hello Hello Goodby

دقت کردی؟ اینجا نخ اصلی منتظر نموند که نخ های فرعی تموم بشن و بره سراغ ادامه کد، برای همین بعد از اجرای نخ های فرعی، ادامه نخ اصلی اجرا شد و Finish هم print شد.
نکته. نخ ها با هم ارتباط دارن. یه آشپز وجود داره که کار اصلیش یا نخ اصلیش این هست که برنج پاک کنه، در کنار این نخ اصلی یه نخ فرعی براش وجود داره که باید قابلمه رو آب کنه و بزار روی گاز تا جوش بیاد! حالا شما تصور کن من برای اون نخ فرعی از join استفاده نکردم تا بگم هرموقع آب جوش اومد، اون موقع بورو سراغ ادامه کار، بلکه وقتی برنج پاک میشه، چون متد join رو صدا نزدم همون موقع برنج هارو میریزه داخل آب صرف نظر از اینکه آب جوش اومده یا نه. حرکت منطقی چی بود اینجا؟ من باید در کنار نخ اصلی، نخ فرعی رو هم میساختم، هردوی اینها همزمان جلو میرفتن، حالا باید شرط قرار میدادم که وقتی نخ اصلی تموم شد، بررسی کنه که نخ فرعی هم تموم شده یا نه (آب جوش اومده یا نه) و اگه اون نخ هم کارش تموم شده بود، برنج هارو میریخت داخل آب.
به این کد دقت کن:

def greet(): for i in range(3): print("Hello") time.sleep(1) for i in range(5): t = threading.Thread(target = greet) t.start()

با اینکار، 5 نخ همزمان راه میندازی که هرکدوم دارن تابع greet رو جداگونه اجرا میکنن.
خروجی:

Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello

حالا کد رو به شکل زیر تغییر میدم:

def greet(): for i in range(3): print("Hello") time.sleep(1) for i in range(5): t = threading.Thread(target = greet) t.start() t.join() print("Finish")

خروجی:

Hello Hello Hello Finish Hello Hello Hello Finish Hello Hello Hello Finish Hello Hello Hello Finish Hello Hello Hello Finish

چون داخل حلقه، بعد از start از join استفاده کردم، منتظر میموند که نخ فرعی به اتمام برسه، و بره سراغ ادامه حلقه تا نخ بعدی ساخته بشه و...
به کد زیر دقت کن:

def greet(name, age): print(f"Name: {name} Age: {age}") names = [("Amirhosein", 21), ("Arta", 19), ("Emad", 30)] for n in names: t = threading.Thread(target = greet, args = n) t.start()

اینجا تابعی داشتم که باید نخ اجراش میکرد و آرگومان هم داشت! برای همین مورد از args تو کلاس Thread استفاده کردم و ورودی هارو در قالب Tuple بهش دادم (حتی اگه یه آرگومان داشت هم باید تو قالب تاپل بهش بدم). مثال:

def greet(name): print(f"Hello {name}") t = threading.Thread(target = greet, args = ("Amirhosein",)) t.start() t.join()

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



2 - Multiprocessing (چندفرآیندی) چیه؟
تصور کن یه لپتاپ داری با 4 هسته. با threading فقط یکی از این هسته ها فعاله (بقیه بیکار) ولی با multiprocessing میتونی به هر هسته یه کار بدی! همزمان همه دارن کار میکنن.
فرق اصلی با threading چیه؟
threading بصورت thread یا نخ ولی multiprocessing بصورت process یا فرآیند اجرا میشه.
threading روی یک هسته اجرا میشه و نخ ها نوبتی (خیلی سریع) اجرا میشن! اما multiprocessing واقعا روی چند هسته اجرا میشه.
برای درک بهتر! تو داری کیک میپزی:
threading یعنی فقط خودتی و باید بین کارا هی جابجا شی.
multiprocessing یعنی 4 تا آدم دیگه هم کمک دارن میکنن! همه با هم مشغولن.
چطوری از multiprocessing استفاده کنیم؟
قدم اول:

import multiprocessing

قدم دوم:

import multiprocessing def Test(): print("Task")

قدم سوم (ساخت و اجرای process):

import multiprocessing def Test(): print("Task") p = multiprocessing.Process(target = Test) p.start() p.join()

تحلیل:
کلاس Process: یه process جدید میسازه (جدا از بقیه کدها)
start: اون فرآیند رو اجرا میکنه (واقعا جدا از هسته/نخ اصلی)
join: منتظر میمونه تا اون process تموم شه
این process کاملا جداست. حافظه و داده هاش جداست. یعنی یه نسخه جدا از پایتون اجرا میشه.
یه نکته. اگه این کد رو اجرا کنی خطا میگیری! برای جلوگیری از Error باید کدت رو توی یه شرط خاص بذاری:

import multiprocessing import time def Test(): for i in range(5, 0, -1): print(f"Shomaresh Gar: {i}") time.sleep(1) if __name__ == "__main__": p = multiprocessing.Process(target = Test) p.start() p.join() print("Process Finish")

چرا این شرط لازمه؟ وقتی یک process قراره ساخته بشه، کد اون فایل داخل یک process دیگه توسط پایتون اجرا میشه (یعنی فایل فعلی الان با python تو هسته 1 فعال هست و داره کار میکنه، حالا وقتی رسید که خطی که من process دیگه ایی تعریف میکنم، میاد فایل رو میبره تو هسته 2 و اونجا با پایتون بصورت مجزا اجراش میکنه، برای همین کدها مجدد از اول خونده میشه و اگه قرار باشه اونجا هم دوباره برسه به خط تولید process و مجدد این چرخه تکرار بشه برنامه کرش میکنه. به زبان ساده تر...
فرض کن اسکریپتت اسمش main.py هست.
وقتی پایتون میخواد یه process جدید بسازه:
دوباره فایل main.py رو اجرا میکنه.
پس اگه این شرط نباشه، خود پایتون دوباره همون کد رو اجرا میکنه.
دوباره به خط (...)p = Process میرسه.
دوباره یه process جدید میسازه...
و این چرخه تکرار میشه تا کرش!
ولی وقتی بنویسی:

if __name__ == "__main__":

پایتون میگه فقط وقتی مستقیما داری فایل اصلی رو اجرا میکنی این کدها اجرا بشن، نه وقتی یه process جدید ساخته میشه. به این کد دقت کن:

import multiprocessing print("Test") def Test(): print("Task") if __name__ == "__main__": Test_Process = multiprocessing.Process(target = Test) Test_Process.start() Test_Process.join()

خروجی:

Test Test Task

برای اینکه خط print("Test") فقط یه بار اجرا بشه باید اون خط رو هم بذاری داخل شرط. مثال:

import multiprocessing def Test(): print("Task") if __name__ == "__main__": print("Test") Test_Process = multiprocessing.Process(target = Test) Test_Process.start() Test_Process.join()

خروجی:

Test Task


به این کد دقت کن:

def heavy_calc(): count = 0 for i in range(10**7): count += i

تو قدم اول میخوام با threading اجراش کنم:

def heavy_calc(): count = 0 for i in range(10**8): count += i import threading, time start = time.time() t1 = threading.Thread(target=heavy_calc) t2 = threading.Thread(target=heavy_calc) t1.start() t2.start() t1.join() t2.join() print("Time Run: ", time.time() - start)

خروجی:

Time Run: 6.048577547073364

حالا میخوام با multiprocessing اجراش کنم:

def heavy_calc(): count = 0 for i in range(10**8): count += i import multiprocessing, time start = time.time() p1 = multiprocessing.Process(target=heavy_calc) p2 = multiprocessing.Process(target=heavy_calc) if __name__ == "__main__": p1.start() p2.start() p1.join() p2.join() print("Time Run: ", time.time() - start)

خروجی:

Time Run: 3.5271332263946533

تو این حالت چون دوتا هسته همزمان درگیر هستن زمان کمتری برای پردازش گذاشته شد.
یه سوال! اگه برنامه ایی بنویسی که از چند هسته استفاده کنه (مثلا با multiprocessing) و بعد یه نفر بیاد روی سیستمش که فقط 1 هسته داره اجراش کنه، دقیقا چی میشه؟ برنامه بدون مشکل اجرا میشه. اما موازی واقعی اتفاق نمیافته. یعنی فرآیندها یکی یکی و نوبتی اجرا میشن، نه همزمان.



3 - asyncio یا asynchronous (برنامه نویسی ناهمگام) چیه؟
asyncio یه راه برای پیادهسازی همزمانی (Concurrency) توی پایتونه که بر پایهی چیزیه به اسم async/await.
این روش به جای اینکه مثل threading یا multiprocessing از چند Thread یا Process استفاده کنه، فقط یه Thread داره، ولی اون رو هوشمندانه بین چند کار تقسیم میکنه. به زبون ساده! asyncio یعنی:
تا وقتی یه کاری منتظره (مثلا منتظره چیزی از اینترنت بخونه)، وقت رو تلف نکن! سریع برو یه کار دیگه انجام بده. وقتی اون کار تموم شد، برگرد سر این یکی.
چطوری از asyncio استفاده کنیم؟
فرض کن ما دوتا کار داریم که باید انجام بشن. میخوایم اونا رو همزمان انجام بدیم، ولی فقط با یه نخ و بدون threading. کد:

import asyncio async def task1(): print("Start Task1") await asyncio.sleep(2) print("End Task1") async def task2(): print("Start task2") await asyncio.sleep(1) print("End task2") async def main(): await asyncio.gather(task1(), task2()) # اجرای همزمان توابع asyncio.run(main())

تو این کد داریم دو تا کار (task) تعریف میکنیم. هر دوشون:
یه متن چاپ میکنن
یه مدت صبر میکنن (با sleep)
یه متن دیگه چاپ میکنن
ولی این کارو به شکل همزمان (concurrent) انجام میدن! یعنی در همون زمانی که یکی منتظره، اون یکی اجرا میشه. این کارو با کمک asyncio انجام میدیم.
تحلیل خط به خط:
کلمه async جلوی def یعنی این تابع از نوع غیرهمزمان (asynchronous) هست. فرق این تابع با تابعهای معمولی اینه که:
نمیتونی مستقیم صداش بزنی
باید یا با await صداش بزنی
یا داخل یه تابع async دیگه استفادش کنی
await asyncio.sleep(2): کلمه await یعنی الان یه کار async قراره انجام بشه که باید منتظر بمونیم تا تموم بشه. ولی در این مدت بیکار نمیشیم، میریم سراغ کار بعدی. در ادامه asyncio.sleep(2) یعنی دو ثانیه صبر کن، ولی به روش async نه با time.sleep. فرقش با time.sleep(2) اینه که:
تو time.sleep برنامه کامل متوقف میشه.
تو asyncio.sleep برنامه فقط اون تابع رو pause میکنه، بقیه برنامه ادامه پیدا میکنه.
تو خط 13 یه تابع async به اسم main تعریف میکنیم. این تابع قراره تمام taskها رو با هم اجرا کنه.
(...)asyncio.gather یعنی این چندتا تابع async رو باهم اجرا کن و منتظر بمون تا همشون تموم بشن (چون task1 و task2 هر دو async هستن، باید با await صدا زده بشن)
اگه کد بدین شکل بود:

async def main(): await task1() await task2()

اول task1 کامل اجرا میشد، بعد task2. ولی gather باعث میشه همزمان اجرا بشن.
خط آخر: پایتون خودش نمیتونه مستقیم توابع async رو اجرا کنه. پس ما با (...)asyncio.run بهش میگیم:
این تابع async رو اجرا کن، کاراشو انجام بده، بعد برنامه رو ببند.
اینجا main رو اجرا میکنیم (که خودش هم async بود) و توش گفتیم task1 و task2 همزمان اجرا بشن.
خروجی:

Start Task1 Start task2 End task2 End Task1


به کد زیر دقت کنید:

import asyncio async def task1(): c = 0 print("START TASK 1") for i in range(10**9): c += 1 print("END TASK 1") async def task2(): print("START TASK 2") await asyncio.sleep(1) print("END TASK 2") async def main(): await asyncio.gather(task1(), task2()) asyncio.run(main())

خروجی:

START TASK 1 END TASK 1 START TASK 2 END TASK 2

داخل تابع task1 یه حلقه سنگین داریم که قراره 1 میلیارد بار بچرخه! اگر هیچ توقفی (await) داخل حلقه نباشه، کل برنامه رو قفل میکنه.
در ابتدا task1 اجرا میشه، بعد از گذشت زمان زیادی تموم میشه و تازه task2 شروع میشه! چطور کاری کنم که همزمان با task1 تابع دوم یعنی task2 هم اجرا بشه. راه حل:

async def task1(): c = 0 print("START TASK 1") for i in range(10**9): c += 1 if i % 100000 == 0: await asyncio.sleep(0) print("END TASK 1")

هر 100 هزار تکرار یه بار پایتون کار رو متوقف میکنه. به asyncio اجازه میده بره سراغ کارهای دیگه (مثلا اجرای taskهای دیگه). بعد دوباره برمیگرده ادامه حلقه رو انجام میده. بزار دقیق تر بررسی کنیم. مجدد به این کد دقت کن:

import asyncio async def task1(): print("start 1") for i in range(10**6): if i % 100000 == 0: await asyncio.sleep(0) print("end 1") async def task2(): print("start 2") await asyncio.sleep(2) # فقط دو ثانیه میخوابه print("end 2") async def main(): await asyncio.gather(task1(), task2()) asyncio.run(main())

وقتی برنامه به اینجا میرسه:

await asyncio.gather(task1(), task2())

اجرای task1 شروع میشه.
به اولین await asyncio.sleep(0) میرسه، اجازه میده loop بره سراغ task2.
task2 شروع میشه و میرسه به await asyncio.sleep(2)، یعنی دوباره باید صبر کنه!
حالا دوباره task1 فرصت داره ادامه بده.
این جابجایی همینطور ادامه پیدا میکنه تا task2 تموم بشه، بعد task1 هم به آخر برسه.


یه تمرین جالب با threading. به کد زیر دقت کن:

import requests import time def get(url): response = requests.get(url) print(f"status code: {response.status_code}") start_time = time.time() urls = [ "https://www.digikala.com/", "https://www.divar.ir/", "https://www.aparat.com/", "https://snapp.ir/", "https://www.virgool.io/", "https://www.nic.ir/", "https://www.digikala.com/", "https://www.divar.ir/", "https://www.aparat.com/", "https://snapp.ir/", "https://www.virgool.io/", "https://www.nic.ir/", "https://www.digikala.com/", "https://www.divar.ir/", "https://www.aparat.com/", "https://snapp.ir/", "https://www.virgool.io/", "https://www.nic.ir/" ] for url in urls: get(url) print(start_time - time.time())

خروجی: (راجب این توضیح نمیدم که کد چیکار میکنه و...)

-6.172769546508789

حالا همین کد رو با threading مینویسم:

import threading import requests import time def get(url): response = requests.get(url) print(f"status code: {response.status_code}") start_time = time.time() urls = [ "https://www.digikala.com/", "https://www.divar.ir/", "https://www.aparat.com/", "https://snapp.ir/", "https://www.virgool.io/", "https://www.nic.ir/", "https://www.digikala.com/", "https://www.divar.ir/", "https://www.aparat.com/", "https://snapp.ir/", "https://www.virgool.io/", "https://www.nic.ir/", "https://www.digikala.com/", "https://www.divar.ir/", "https://www.aparat.com/", "https://snapp.ir/", "https://www.virgool.io/", "https://www.nic.ir/" ] threads = [threading.Thread(target = get, args = (url, )) for url in urls] for thread in threads: thread.start() for thread in threads: thread.join() print(start_time - time.time())

خروجی:

-1.4165167808532715

تست

برنامه نویسیpythonپایتونکامپیوتر
۳
۲
امیرحسین ناظوری
امیرحسین ناظوری
📕 عاشق یادگیری و به اشتراک‌گذاری دانش -- آیدی من تو شبکه های اجتماعی : mrNazouri13
شاید از این پست‌ها خوشتان بیاید