પાયથોનમાં એક સાથે પ્રોગ્રામિંગની શક્તિને અનલૉક કરો. ઉચ્ચ-પ્રદર્શન, સ્કેલેબલ એપ્લિકેશનો બનાવવા માટે Asyncio કાર્યોને કેવી રીતે બનાવવું, મેનેજ કરવું અને રદ કરવું તે જાણો.
પાયથોન એસિંકિયોમાં નિપુણતા: ટાસ્ક ક્રિએશન અને મેનેજમેન્ટમાં ઊંડાણપૂર્વક
આધુનિક સોફ્ટવેર ડેવલપમેન્ટની દુનિયામાં, પ્રદર્શન સર્વોપરી છે. એપ્લિકેશનો પ્રતિભાવશીલ હોવાની અપેક્ષા છે, જે હજારો એક સાથે નેટવર્ક કનેક્શન્સ, ડેટાબેઝ ક્વેરીઝ અને API કૉલ્સને પરસેવો પાડ્યા વિના હેન્ડલ કરે છે. I/O-બાઉન્ડ ઓપરેશન્સ માટે—જ્યાં પ્રોગ્રામ નેટવર્ક અથવા ડિસ્ક જેવા બાહ્ય સંસાધનોની રાહ જોવામાં તેનો મોટાભાગનો સમય વિતાવે છે—પરંપરાગત સિંક્રોનસ કોડ નોંધપાત્ર અવરોધ બની શકે છે. આ તે છે જ્યાં એસિંક્રોનસ પ્રોગ્રામિંગ ચમકે છે, અને પાયથોનની asyncio
લાઇબ્રેરી આ શક્તિને અનલૉક કરવાની ચાવી છે.
asyncio
ના એક સાથે મોડેલના હૃદયમાં એક સરળ પરંતુ શક્તિશાળી ખ્યાલ રહેલો છે: ટાસ્ક. જ્યારે કોરૂટિન્સ વ્યાખ્યાયિત કરે છે કે શું કરવું, ત્યારે ટાસ્ક એ છે જે ખરેખર વસ્તુઓ કરે છે. તે એક સાથે એક્ઝેક્યુશનનું મૂળભૂત એકમ છે, જે તમારા પાયથોન પ્રોગ્રામ્સને એક સાથે અનેક કામગીરીને જગલ કરવાની મંજૂરી આપે છે, જે થ્રુપુટ અને પ્રતિભાવમાં નાટ્યાત્મક રીતે સુધારો કરે છે.
આ વ્યાપક માર્ગદર્શિકા તમને asyncio.Task
માં ઊંડાણપૂર્વક લઈ જશે. અમે સર્જનની મૂળભૂત બાબતોથી લઈને અદ્યતન મેનેજમેન્ટ પેટર્ન, રદ અને શ્રેષ્ઠ પ્રથાઓ સુધીની દરેક વસ્તુનું અન્વેષણ કરીશું. પછી ભલે તમે હાઇ-ટ્રાફિક વેબ સર્વિસ, ડેટા સ્ક્રેપિંગ ટૂલ અથવા રીઅલ-ટાઇમ એપ્લિકેશન બનાવી રહ્યા હોવ, કાર્યોમાં નિપુણતા મેળવવી એ કોઈપણ આધુનિક પાયથોન ડેવલપર માટે આવશ્યક કૌશલ્ય છે.
કોરૂટિન શું છે? ઝડપી તાજું
દોડતા પહેલા, આપણે ચાલવું જોઈએ. અને asyncio
ની દુનિયામાં, ચાલવું એ કોરૂટિન્સને સમજવું છે. કોરૂટિન એ async def
સાથે વ્યાખ્યાયિત થયેલ વિશિષ્ટ પ્રકારનું કાર્ય છે.
જ્યારે તમે નિયમિત પાયથોન ફંક્શનને કૉલ કરો છો, ત્યારે તે શરૂઆતથી અંત સુધી એક્ઝિક્યુટ થાય છે. જ્યારે તમે કોરૂટિન ફંક્શનને કૉલ કરો છો, ત્યારે તે તરત જ એક્ઝિક્યુટ થતું નથી. તેના બદલે, તે કોરૂટિન ઑબ્જેક્ટ પરત કરે છે. આ ઑબ્જેક્ટ એ કરવા માટેના કામ માટેનું બ્લુપ્રિન્ટ છે, પરંતુ તે તેના પોતાના પર નિષ્ક્રિય છે. તે એક થોભેલી ગણતરી છે જેને શરૂ કરી શકાય છે, સસ્પેન્ડ કરી શકાય છે અને ફરી શરૂ કરી શકાય છે.
import asyncio
async def say_hello(name: str):
print(f"Preparing to greet {name}...")
await asyncio.sleep(1) # Simulate a non-blocking I/O operation
print(f"Hello, {name}!")
# Calling the function doesn't run it, it creates a coroutine object
coro = say_hello("World")
print(f"Created a coroutine object: {coro}")
# To actually run it, you need to use an entry point like asyncio.run()
# asyncio.run(coro)
જાદુઈ કીવર્ડ await
છે. તે ઇવેન્ટ લૂપને કહે છે, "આ કામગીરીમાં થોડો સમય લાગી શકે છે, તેથી મને અહીં થોભાવવા અને બીજું કંઈક કામ કરવા માટે નિઃસંકોચ રહો. જ્યારે આ કામગીરી પૂર્ણ થાય ત્યારે મને જગાડો." થોભાવવાની અને સંદર્ભો બદલવાની આ ક્ષમતા એ છે જે એક સાથે કામગીરીને સક્ષમ કરે છે.
એક સાથે ચાલવાનું હૃદય: asyncio.Task ને સમજવું
તેથી, કોરૂટિન એ બ્લુપ્રિન્ટ છે. રસોડાને (ઇવેન્ટ લૂપ) રસોઈ શરૂ કરવાનું કેવી રીતે કહેવું? આ તે છે જ્યાં asyncio.Task
આવે છે.
asyncio.Task
એ એક ઑબ્જેક્ટ છે જે કોરૂટિનને આવરિત કરે છે અને તેને asyncio ઇવેન્ટ લૂપ પર એક્ઝેક્યુશન માટે સુનિશ્ચિત કરે છે. આ રીતે વિચારો:
- કોરૂટિન (
async def
): વાનગી માટેની વિગતવાર રેસીપી. - ઇવેન્ટ લૂપ: કેન્દ્રીય રસોડું જ્યાં તમામ રસોઈ થાય છે.
await my_coro()
: તમે રસોડામાં ઊભા છો અને રેસીપીને પગલું દ્વારા અનુસરો છો. વાનગી પૂર્ણ ન થાય ત્યાં સુધી તમે બીજું કંઈ કરી શકતા નથી. આ ક્રમિક અમલ છે.asyncio.create_task(my_coro())
: તમે રસોડામાં રસોઈયાને (ટાસ્ક) રેસીપી આપો છો અને કહો છો, "આના પર કામ કરવાનું શરૂ કરો." રસોઈયો તરત જ શરૂ કરે છે, અને તમે અન્ય વસ્તુઓ કરવા માટે સ્વતંત્ર છો, જેમ કે વધુ વાનગીઓ સોંપવી. આ એક સાથે અમલ છે.
મુખ્ય તફાવત એ છે કે asyncio.create_task()
કોરૂટિનને "બેકગ્રાઉન્ડમાં" ચલાવવા માટે સુનિશ્ચિત કરે છે અને તરત જ તમારા કોડને નિયંત્રણ પરત કરે છે. તમને Task
ઑબ્જેક્ટ પાછો મળે છે, જે આ ચાલુ કામગીરી માટે હેન્ડલ તરીકે કાર્ય કરે છે. તમે આ હેન્ડલનો ઉપયોગ તેની સ્થિતિ તપાસવા, તેને રદ કરવા અથવા પછીથી તેના પરિણામની રાહ જોવા માટે કરી શકો છો.
તમારા પ્રથમ કાર્યો બનાવવું: `asyncio.create_task()` કાર્ય
ટાસ્ક બનાવવાની પ્રાથમિક રીત એ asyncio.create_task()
કાર્ય સાથે છે. તે કોરૂટિન ઑબ્જેક્ટને તેના દલીલ તરીકે લે છે અને તેને એક્ઝેક્યુશન માટે સુનિશ્ચિત કરે છે.
મૂળભૂત સિન્ટેક્સ
ઉપયોગ સીધો છે:
import asyncio
async def my_background_work():
print("Starting background work...")
await asyncio.sleep(2)
print("Background work finished.")
return "Success"
async def main():
print("Main function started.")
# Schedule my_background_work to run concurrently
task = asyncio.create_task(my_background_work())
# While the task runs, we can do other things
print("Task created. Main function continues to run.")
await asyncio.sleep(1)
print("Main function did some other work.")
# Now, wait for the task to complete and get its result
result = await task
print(f"Task completed with result: {result}")
asyncio.run(main())
ધ્યાન આપો કે આઉટપુટ કેવી રીતે બતાવે છે કે `main` કાર્ય કાર્ય બનાવ્યા પછી તરત જ તેનું એક્ઝેક્યુશન ચાલુ રાખે છે. તે બ્લોક કરતું નથી. જ્યારે આપણે અંતે સ્પષ્ટપણે `await task` કરીએ છીએ ત્યારે જ તે થોભાવે છે.
વ્યવહારુ ઉદાહરણ: એક સાથે વેબ વિનંતીઓ
ચાલો સામાન્ય પરિસ્થિતિ સાથે કાર્યોની વાસ્તવિક શક્તિ જોઈએ: બહુવિધ URL થી ડેટા લાવવો. આ માટે, અમે લોકપ્રિય `aiohttp` લાઇબ્રેરીનો ઉપયોગ કરીશું, જેને તમે `pip install aiohttp` સાથે ઇન્સ્ટોલ કરી શકો છો.
પ્રથમ, ચાલો ક્રમિક (ધીમી) રીત જોઈએ:
import asyncio
import aiohttp
import time
async def fetch_status(session, url):
async with session.get(url) as response:
return response.status
async def main_sequential():
urls = [
"https://www.python.org",
"https://www.google.com",
"https://www.github.com",
"https://www.microsoft.com"
]
start_time = time.time()
async with aiohttp.ClientSession() as session:
for url in urls:
status = await fetch_status(session, url)
print(f"Status for {url}: {status}")
end_time = time.time()
print(f"Sequential execution took {end_time - start_time:.2f} seconds")
# To run this, you would use: asyncio.run(main_sequential())
જો દરેક વિનંતીમાં લગભગ 0.5 સેકન્ડ લાગે છે, તો કુલ સમય આશરે 2 સેકન્ડ હશે, કારણ કે દરેક `await` તે એક વિનંતી પૂર્ણ ન થાય ત્યાં સુધી લૂપને બ્લોક કરે છે.
હવે, ચાલો કાર્યો સાથે એક સાથે ચાલવાની શક્તિને છૂટા કરીએ:
import asyncio
import aiohttp
import time
# fetch_status coroutine remains the same
async def fetch_status(session, url):
async with session.get(url) as response:
return response.status
async def main_concurrent():
urls = [
"https://www.python.org",
"https://www.google.com",
"https://www.github.com",
"https://www.microsoft.com"
]
start_time = time.time()
async with aiohttp.ClientSession() as session:
# Create a list of tasks, but don't await them yet
tasks = [asyncio.create_task(fetch_status(session, url)) for url in urls]
# Now, wait for all tasks to complete
statuses = await asyncio.gather(*tasks)
for url, status in zip(urls, statuses):
print(f"Status for {url}: {status}")
end_time = time.time()
print(f"Concurrent execution took {end_time - start_time:.2f} seconds")
asyncio.run(main_concurrent())
જ્યારે તમે એક સાથે વર્ઝન ચલાવો છો, ત્યારે તમને નાટ્યાત્મક તફાવત દેખાશે. કુલ સમય લગભગ સૌથી લાંબી એક વિનંતીનો સમય હશે, બધાના સરવાળાનો નહીં. આ એટલા માટે છે કારણ કે જેવી જ પહેલી `fetch_status` કોરૂટિન તેની `await session.get(url)` પર આવે છે, ઇવેન્ટ લૂપ તેને થોભાવે છે અને તરત જ આગલી શરૂ કરે છે. તમામ નેટવર્ક વિનંતીઓ અસરકારક રીતે એક જ સમયે થાય છે.
કાર્યોના સમૂહનું સંચાલન: આવશ્યક પેટર્ન
વ્યક્તિગત કાર્યો બનાવવાનું મહાન છે, પરંતુ વાસ્તવિક દુનિયાની એપ્લિકેશન્સમાં, તમારે વારંવાર તેમને લોન્ચ કરવા, મેનેજ કરવા અને સમન્વયિત કરવા પડે છે. `asyncio` આ માટે ઘણા શક્તિશાળી સાધનો પૂરા પાડે છે.
આધુનિક અભિગમ (પાયથોન 3.11+): `asyncio.TaskGroup`
પાયથોન 3.11 માં રજૂ કરવામાં આવેલ, `TaskGroup` એ સંબંધિત કાર્યોના સમૂહને સંચાલિત કરવાની નવી, ભલામણ કરેલ અને સલામત રીત છે. તે સ્ટ્રક્ચર્ડ એક સાથે શું કહેવાય છે તે પ્રદાન કરે છે.
`TaskGroup`ની મુખ્ય સુવિધાઓ:
- બાંયધરીકૃત સફાઈ: `async with` બ્લોક ત્યાં સુધી બહાર નીકળશે નહીં જ્યાં સુધી તેમાં બનાવેલ તમામ કાર્યો પૂર્ણ ન થાય.
- મજબૂત ભૂલ હેન્ડલિંગ: જો જૂથની અંદરનું કોઈપણ કાર્ય અપવાદ ઉભો કરે છે, તો જૂથના અન્ય તમામ કાર્યો આપમેળે રદ થઈ જાય છે, અને `async with` બ્લોકમાંથી બહાર નીકળ્યા પછી અપવાદ (અથવા `ExceptionGroup`) ફરીથી ઉભો કરવામાં આવે છે. આ અનાથ કાર્યોને અટકાવે છે અને અનુમાનિત સ્થિતિને સુનિશ્ચિત કરે છે.
તેનો ઉપયોગ કેવી રીતે કરવો તે અહીં છે:
import asyncio
async def worker(delay):
print(f"Worker starting, will sleep for {delay}s")
await asyncio.sleep(delay)
# This worker will fail
if delay == 2:
raise ValueError("Something went wrong in worker 2")
print(f"Worker with delay {delay} finished")
return f"Result from {delay}s"
async def main():
print("Starting main with TaskGroup...")
try:
async with asyncio.TaskGroup() as tg:
task1 = tg.create_task(worker(1))
task2 = tg.create_task(worker(2)) # This one will fail
task3 = tg.create_task(worker(3))
print("Tasks created in the group.")
# This part of the code will NOT be reached if an exception occurs
# The results would be accessed via task1.result(), etc.
print("All tasks completed successfully.")
except* ValueError as eg: # Note the `except*` for ExceptionGroup
print(f"Caught an exception group with {len(eg.exceptions)} exceptions.")
for exc in eg.exceptions:
print(f" - {exc}")
print("Main function finished.")
asyncio.run(main())
જ્યારે તમે આ ચલાવો છો, ત્યારે તમને દેખાશે કે `worker(2)` ભૂલ ઉભો કરે છે. `TaskGroup` આને પકડે છે, અન્ય ચાલી રહેલા કાર્યોને રદ કરે છે (જેમ કે `worker(3)`), અને પછી `ValueError` ધરાવતું `ExceptionGroup` ઉભો કરે છે. આ પેટર્ન વિશ્વસનીય સિસ્ટમો બનાવવા માટે અતિ મજબૂત છે.
ક્લાસિક વર્કહોર્સ: `asyncio.gather()`
`TaskGroup` પહેલાં, `asyncio.gather()` એ એક સાથે બહુવિધ оживаbles ચલાવવાની અને તે બધા પૂર્ણ થવાની રાહ જોવાની સૌથી સામાન્ય રીત હતી.
gather()
કોરૂટિન્સ અથવા કાર્યોનો ક્રમ લે છે, તે બધાને ચલાવે છે અને ઇનપુટ્સની સમાન ક્રમમાં તેમના પરિણામોની સૂચિ પરત કરે છે. તે સામાન્ય કેસ માટે ઉચ્ચ-સ્તરનું, અનુકૂળ કાર્ય છે "આ બધી વસ્તુઓ ચલાવો અને મને બધા પરિણામો આપો."
import asyncio
async def fetch_data(source, delay):
print(f"Fetching from {source}...")
await asyncio.sleep(delay)
return {"source": source, "data": f"some data from {source}"}
async def main():
# gather can take coroutines directly
results = await asyncio.gather(
fetch_data("API", 2),
fetch_data("Database", 3),
fetch_data("Cache", 1)
)
print(results)
asyncio.run(main())
`gather()` સાથે ભૂલ હેન્ડલિંગ: મૂળભૂત રીતે, જો `gather()` માંથી પસાર થતાં કોઈપણ оживаbles અપવાદ ઉભો કરે છે, તો `gather()` તરત જ તે અપવાદનો પ્રચાર કરે છે, અને અન્ય ચાલી રહેલા કાર્યો રદ થઈ જાય છે. તમે `return_exceptions=True` સાથે આ વર્તણૂકને બદલી શકો છો. આ મોડમાં, અપવાદ ઉભો કરવાને બદલે, તેને અનુરૂપ સ્થિતિ પર પરિણામોની સૂચિમાં મૂકવામાં આવશે.
# ... inside main()
results = await asyncio.gather(
fetch_data("API", 2),
asyncio.create_task(worker(1)), # This will raise a ValueError
fetch_data("Cache", 1),
return_exceptions=True
)
# results will contain a mix of successful results and exception objects
print(results)
ફાઇન-ગ્રેઇન્ડ કંટ્રોલ: `asyncio.wait()`
asyncio.wait()
એ એક નીચલા-સ્તરનું કાર્ય છે જે કાર્યોના જૂથ પર વધુ વિગતવાર નિયંત્રણ પ્રદાન કરે છે. `gather()`થી વિપરીત, તે સીધા પરિણામો પરત કરતું નથી. તેના બદલે, તે કાર્યોના બે સમૂહો પરત કરે છે: `done` અને `pending`.
તેની સૌથી શક્તિશાળી વિશેષતા એ `return_when` પેરામીટર છે, જે આ હોઈ શકે છે:
asyncio.ALL_COMPLETED
(મૂળભૂત): જ્યારે બધા કાર્યો પૂર્ણ થાય ત્યારે પરત કરે છે.asyncio.FIRST_COMPLETED
: ઓછામાં ઓછું એક કાર્ય પૂર્ણ થતાં જ પરત કરે છે.asyncio.FIRST_EXCEPTION
: જ્યારે કોઈ કાર્ય અપવાદ ઉભો કરે ત્યારે પરત કરે છે. જો કોઈ કાર્ય અપવાદ ઉભો કરતું નથી, તો તે `ALL_COMPLETED` ની સમકક્ષ છે.
આ બહુવિધ રીડન્ડન્ટ ડેટા સ્રોતોને ક્વેરી કરવા અને પ્રતિસાદ આપનાર પ્રથમનો ઉપયોગ કરવા જેવી પરિસ્થિતિઓ માટે અત્યંત ઉપયોગી છે:
import asyncio
async def query_source(name, delay):
await asyncio.sleep(delay)
return f"Result from {name}"
async def main():
tasks = [
asyncio.create_task(query_source("Fast Mirror", 0.5)),
asyncio.create_task(query_source("Slow Main DB", 2.0)),
asyncio.create_task(query_source("Geographic Replica", 0.8))
]
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
# Get the result from the completed task
first_result = done.pop().result()
print(f"Got first result: {first_result}")
# We now have pending tasks that are still running. It's crucial to clean them up!
print(f"Cancelling {len(pending)} pending tasks...")
for task in pending:
task.cancel()
# Await the cancelled tasks to allow them to process the cancellation
await asyncio.gather(*pending, return_exceptions=True)
print("Cleanup complete.")
asyncio.run(main())
TaskGroup વિ. gather() વિ. wait(): ક્યારે કોનો ઉપયોગ કરવો?
- તમારી મૂળભૂત પસંદગી તરીકે `asyncio.TaskGroup` (પાયથોન 3.11+) નો ઉપયોગ કરો. તેનું સ્ટ્રક્ચર્ડ એક સાથે મોડેલ સલામત, સ્વચ્છ અને ભૂલની સંભાવના ઓછી છે જે કાર્યોના જૂથને મેનેજ કરવા માટે જે એક જ તાર્કિક કામગીરીના છે.
- `asyncio.gather()` નો ઉપયોગ કરો જ્યારે તમારે સ્વતંત્ર કાર્યોના જૂથને ચલાવવાની જરૂર હોય અને ફક્ત તેમના પરિણામોની સૂચિ જોઈએ છે. તે હજી પણ ખૂબ ઉપયોગી છે અને સરળ કેસો માટે થોડો વધુ સંક્ષિપ્ત છે, ખાસ કરીને 3.11 પહેલાંના પાયથોન સંસ્કરણોમાં.
- `asyncio.wait()` નો ઉપયોગ કરો અદ્યતન પરિસ્થિતિઓ માટે જ્યાં તમારે પૂર્ણતાની શરતો પર ફાઇન-ગ્રેઇન્ડ નિયંત્રણની જરૂર હોય (દા.ત., પ્રથમ પરિણામની રાહ જોવી) અને બાકી રહેલા બાકી કાર્યોને મેન્યુઅલી મેનેજ કરવા માટે તૈયાર છો.
ટાસ્ક લાઇફસાયકલ અને મેનેજમેન્ટ
એકવાર ટાસ્ક બનાવવામાં આવે, પછી તમે `Task` ઑબ્જેક્ટ પરની પદ્ધતિઓનો ઉપયોગ કરીને તેની સાથે ક્રિયાપ્રતિક્રિયા કરી શકો છો.
ટાસ્ક સ્ટેટસ તપાસી રહ્યું છે
task.done()
: જો ટાસ્ક પૂર્ણ થઈ ગયું હોય તો `True` પરત કરે છે (કાં તો સફળતાપૂર્વક, અપવાદ સાથે અથવા રદ કરીને).task.cancelled()
: જો ટાસ્ક રદ કરવામાં આવ્યું હોય તો `True` પરત કરે છે.task.exception()
: જો ટાસ્કે અપવાદ ઉભો કર્યો હોય, તો આ અપવાદ ઑબ્જેક્ટ પરત કરે છે. નહિંતર, તે `None` પરત કરે છે. તમે આને ટાસ્ક `done()` થયા પછી જ કૉલ કરી શકો છો.
પરિણામો પુનઃપ્રાપ્ત કરી રહ્યા છીએ
ટાસ્કનું પરિણામ મેળવવાની મુખ્ય રીત એ છે કે ફક્ત `await task`. જો ટાસ્ક સફળતાપૂર્વક પૂર્ણ થયું હોય, તો આ મૂલ્ય પરત કરે છે. જો તેણે અપવાદ ઉભો કર્યો હોય, તો `await task` તે અપવાદને ફરીથી ઉભો કરશે. જો તે રદ કરવામાં આવ્યું હોય, તો `await task` `CancelledError` ઉભો કરશે.
વૈકલ્પિક રીતે, જો તમને ખબર હોય કે ટાસ્ક `done()` છે, તો તમે `task.result()` કૉલ કરી શકો છો. આ મૂલ્યો પરત કરવા અથવા અપવાદો ઉભા કરવાના સંદર્ભમાં `await task` જેવું જ વર્તન કરે છે.
રદ કરવાની કળા
મજબૂત એપ્લિકેશનો બનાવવા માટે લાંબા સમયથી ચાલતી કામગીરીને સુંદર રીતે રદ કરવામાં સક્ષમ બનવું નિર્ણાયક છે. તમારે સમયસમાપ્તિ, વપરાશકર્તા વિનંતી અથવા સિસ્ટમમાં અન્યત્ર ભૂલને કારણે ટાસ્ક રદ કરવાની જરૂર પડી શકે છે.
તમે તેના task.cancel()
મેથડને કૉલ કરીને ટાસ્ક રદ કરો છો. જો કે, આ તરત જ ટાસ્કને રોકતું નથી. તેના બદલે, તે આગલા await
પોઇન્ટ પર કોરૂટિનની અંદર ફેંકવા માટે `CancelledError` અપવાદને સુનિશ્ચિત કરે છે. આ એક મહત્વપૂર્ણ વિગત છે. તે કોરૂટિનને બહાર નીકળતા પહેલા સાફ કરવાની તક આપે છે.
સારી રીતે વર્તેલા કોરૂટિનએ આ `CancelledError`ને સુંદર રીતે હેન્ડલ કરવું જોઈએ, સામાન્ય રીતે `try...finally` બ્લોકનો ઉપયોગ કરીને એ સુનિશ્ચિત કરવા માટે કે ફાઇલ હેન્ડલ્સ અથવા ડેટાબેઝ કનેક્શન્સ જેવા સંસાધનો બંધ છે.
import asyncio
async def resource_intensive_task():
print("Acquiring resource (e.g., opening a connection)...")
try:
for i in range(10):
print(f"Working... step {i+1}")
await asyncio.sleep(1) # This is an await point where CancelledError can be injected
except asyncio.CancelledError:
print("Task was cancelled! Cleaning up...")
raise # It's good practice to re-raise CancelledError
finally:
print("Releasing resource (e.g., closing connection). This always runs.")
async def main():
task = asyncio.create_task(resource_intensive_task())
# Let it run for a bit
await asyncio.sleep(2.5)
print("Main decides to cancel the task.")
task.cancel()
try:
await task
except asyncio.CancelledError:
print("Main has confirmed the task was cancelled.")
asyncio.run(main())
`finally` બ્લોક એક્ઝિક્યુટ થવાની બાંયધરી છે, જે તેને સફાઈ તર્ક માટે સંપૂર્ણ સ્થાન બનાવે છે.
`asyncio.timeout()` અને `asyncio.wait_for()` સાથે સમયસમાપ્તિ ઉમેરી રહ્યા છીએ
મેન્યુઅલી સૂવું અને રદ કરવું કંટાળાજનક છે. `asyncio` આ સામાન્ય પેટર્ન માટે મદદગારો પૂરા પાડે છે.
પાયથોન 3.11+ માં, `asyncio.timeout()` સંદર્ભ મેનેજર એ પસંદગીની રીત છે:
async def long_running_operation():
await asyncio.sleep(10)
print("Operation finished")
async def main():
try:
async with asyncio.timeout(2): # Set a 2-second timeout
await long_running_operation()
except TimeoutError:
print("The operation timed out!")
asyncio.run(main())
જૂના પાયથોન સંસ્કરણો માટે, તમે `asyncio.wait_for()` નો ઉપયોગ કરી શકો છો. તે સમાન રીતે કાર્ય કરે છે પરંતુ ફંક્શન કૉલમાં ожидаable ને આવરિત કરે છે:
async def main_legacy():
try:
await asyncio.wait_for(long_running_operation(), timeout=2)
except asyncio.TimeoutError:
print("The operation timed out!")
asyncio.run(main_legacy())
બંને સાધનો સમયસમાપ્તિ પર પહોંચે ત્યારે આંતરિક કાર્યને રદ કરીને કાર્ય કરે છે, `TimeoutError` ઉભો કરે છે (જે `CancelledError`નો સબક્લાસ છે).
સામાન્ય ખામીઓ અને શ્રેષ્ઠ પ્રથાઓ
કાર્યો સાથે કામ કરવું શક્તિશાળી છે, પરંતુ ટાળવા માટે થોડા સામાન્ય જાળાઓ છે.
- ખામી: "ફાયર એન્ડ ફર્ગેટ" ભૂલ. `create_task` સાથે કાર્ય બનાવવું અને પછી ક્યારેય તેની રાહ જોવી નહીં (અથવા `TaskGroup` જેવા મેનેજર) જોખમી છે. જો તે કાર્ય અપવાદ ઉભો કરે છે, તો અપવાદ શાંતિથી ખોવાઈ શકે છે, અને તમારો પ્રોગ્રામ કાર્ય પૂર્ણ કરે તે પહેલાં જ બહાર નીકળી શકે છે. દરેક કાર્ય માટે હંમેશા સ્પષ્ટ માલિક રાખો જે તેના પરિણામની રાહ જોવા માટે જવાબદાર છે.
- ખામી: `asyncio.run()`ને `create_task()` સાથે ગૂંચવવું. `asyncio.run(my_coro())` એ `asyncio` પ્રોગ્રામ શરૂ કરવા માટેનું મુખ્ય પ્રવેશદ્વાર છે. તે નવું ઇવેન્ટ લૂપ બનાવે છે અને આપેલ કોરૂટિન પૂર્ણ થાય ત્યાં સુધી ચલાવે છે. `asyncio.create_task(my_coro())` નો ઉપયોગ એક સાથે અમલને સુનિશ્ચિત કરવા માટે પહેલાથી જ ચાલી રહેલા એસિંક ફંક્શનની અંદર થાય છે.
- શ્રેષ્ઠ પ્રથા: આધુનિક પાયથોન માટે `TaskGroup` નો ઉપયોગ કરો. તેની ડિઝાઇન ઘણી સામાન્ય ભૂલોને અટકાવે છે, જેમ કે ભૂલી ગયેલા કાર્યો અને ન સંભાળેલા અપવાદો. જો તમે પાયથોન 3.11 અથવા પછીના વર્ઝન પર છો, તો તેને તમારી ડિફોલ્ટ પસંદગી બનાવો.
- શ્રેષ્ઠ પ્રથા: તમારા કાર્યોને નામ આપો. કાર્ય બનાવતી વખતે, `name` પેરામીટરનો ઉપયોગ કરો: `asyncio.create_task(my_coro(), name='DataProcessor-123')`. આ ડીબગીંગ માટે અમૂલ્ય છે. જ્યારે તમે બધા ચાલી રહેલા કાર્યોની સૂચિ બનાવો છો, ત્યારે અર્થપૂર્ણ નામો હોવાથી તમને તમારા પ્રોગ્રામ શું કરી રહ્યું છે તે સમજવામાં મદદ મળે છે.
- શ્રેષ્ઠ પ્રથા: સુંદર શટડાઉન સુનિશ્ચિત કરો. જ્યારે તમારી એપ્લિકેશનને શટડાઉન કરવાની જરૂર હોય, ત્યારે ખાતરી કરો કે તમારી પાસે ચાલી રહેલા તમામ બેકગ્રાઉન્ડ કાર્યોને રદ કરવાની અને તેમને યોગ્ય રીતે સાફ થાય તેની રાહ જોવાની પદ્ધતિ છે.
અદ્યતન ખ્યાલો: એક ઝલક બહાર
ડીબગીંગ અને આત્મનિરીક્ષણ માટે, `asyncio` થોડા ઉપયોગી કાર્યો પૂરા પાડે છે:
asyncio.current_task()
: હાલમાં ચાલી રહેલા કોડ માટે `Task` ઑબ્જેક્ટ પરત કરે છે.asyncio.all_tasks()
: ઇવેન્ટ લૂપ દ્વારા હાલમાં સંચાલિત તમામ `Task` ઑબ્જેક્ટનો સમૂહ પરત કરે છે. આ ડીબગીંગ માટે મહાન છે કે શું ચાલી રહ્યું છે તે જોવા માટે.
તમે `task.add_done_callback()` નો ઉપયોગ કરીને કાર્યોમાં પૂર્ણતા કોલબેક્સ પણ જોડી શકો છો. જ્યારે આ ઉપયોગી થઈ શકે છે, ત્યારે તે ઘણીવાર વધુ જટિલ, કોલબેક-શૈલી કોડ સ્ટ્રક્ચર તરફ દોરી જાય છે. `await`, `TaskGroup` અથવા `gather` નો ઉપયોગ કરીને આધુનિક અભિગમો સામાન્ય રીતે વાંચનક્ષમતા અને જાળવણી માટે પસંદ કરવામાં આવે છે.
નિષ્કર્ષ
આધુનિક પાયથોનમાં `asyncio.Task` એ એક સાથે ચાલવાનું એન્જિન છે. કાર્યોના જીવનચક્રને કેવી રીતે બનાવવું, મેનેજ કરવું અને સુંદર રીતે હેન્ડલ કરવું તે સમજીને, તમે તમારી I/O-બાઉન્ડ એપ્લિકેશનોને ધીમી, ક્રમિક પ્રક્રિયાઓથી અત્યંત કાર્યક્ષમ, સ્કેલેબલ અને પ્રતિભાવશીલ સિસ્ટમમાં રૂપાંતરિત કરી શકો છો.
અમે `create_task()` સાથે કોરૂટિનને સુનિશ્ચિત કરવાના મૂળભૂત ખ્યાલથી લઈને `TaskGroup`, `gather()` અને `wait()` સાથે જટિલ વર્કફ્લોને ગોઠવવા સુધીની સફરને આવરી લીધી છે. અમે સ્થિતિસ્થાપક સોફ્ટવેર બનાવવા માટે મજબૂત ભૂલ હેન્ડલિંગ, રદ અને સમયસમાપ્તિના નિર્ણાયક મહત્વની પણ શોધ કરી છે.
એસિંક્રોનસ પ્રોગ્રામિંગની દુનિયા વિશાળ છે, પરંતુ કાર્યોમાં નિપુણતા મેળવવી એ તમે લઈ શકો તેવું સૌથી મહત્વપૂર્ણ પગલું છે. પ્રયોગ કરવાનું શરૂ કરો. તમારી એપ્લિકેશનના ક્રમિક, I/O-બાઉન્ડ ભાગને એક સાથે કાર્યોનો ઉપયોગ કરવા માટે કન્વર્ટ કરો અને તમારા માટે પ્રદર્શન લાભો જુઓ. એક સાથે ચાલવાની શક્તિને સ્વીકારો, અને તમે ઉચ્ચ-પ્રદર્શન પાયથોન એપ્લિકેશનોની આગામી પેઢી બનાવવા માટે સારી રીતે સજ્જ થશો.