પાયથોનના મલ્ટીપ્રોસેસિંગ મોડ્યુલ માટે એક વ્યાપક માર્ગદર્શિકા, જે સમાંતર અમલીકરણ માટે પ્રોસેસ પૂલ્સ અને ડેટા શેરિંગ માટે શેર્ડ મેમરી મેનેજમેન્ટ પર ધ્યાન કેન્દ્રિત કરે છે. તમારા પાયથોન એપ્લિકેશન્સને પ્રદર્શન અને સ્કેલેબિલિટી માટે ઓપ્ટિમાઇઝ કરો.
પાયથોન મલ્ટીપ્રોસેસિંગ: પ્રોસેસ પૂલ્સ અને શેર્ડ મેમરીમાં નિપુણતા
પાયથોન, તેની સુઘડતા અને વૈવિધ્યતા હોવા છતાં, ગ્લોબલ ઇન્ટરપ્રિટર લોક (GIL) ને કારણે વારંવાર પ્રદર્શનની સમસ્યાઓનો સામનો કરે છે. GIL એક સમયે માત્ર એક જ થ્રેડને પાયથોન ઇન્ટરપ્રિટરનું નિયંત્રણ રાખવાની મંજૂરી આપે છે. આ મર્યાદા CPU-બાઉન્ડ કાર્યોને નોંધપાત્ર રીતે અસર કરે છે, જે મલ્ટિથ્રેડેડ એપ્લિકેશન્સમાં સાચા સમાંતરવાદને અવરોધે છે. આ પડકારને પાર કરવા માટે, પાયથોનનું multiprocessing મોડ્યુલ બહુવિધ પ્રક્રિયાઓનો લાભ લઈને એક શક્તિશાળી ઉકેલ પૂરો પાડે છે, જે અસરકારક રીતે GIL ને બાયપાસ કરે છે અને સાચા સમાંતર અમલને સક્ષમ કરે છે.
આ વ્યાપક માર્ગદર્શિકા પાયથોન મલ્ટિપ્રોસેસિંગના મુખ્ય ખ્યાલો, ખાસ કરીને પ્રોસેસ પૂલ્સ અને શેર્ડ મેમરી મેનેજમેન્ટ પર ધ્યાન કેન્દ્રિત કરે છે. અમે અન્વેષણ કરીશું કે કેવી રીતે પ્રોસેસ પૂલ્સ સમાંતર કાર્ય અમલને સુવ્યવસ્થિત કરે છે અને કેવી રીતે શેર્ડ મેમરી પ્રક્રિયાઓ વચ્ચે કાર્યક્ષમ ડેટા શેરિંગની સુવિધા આપે છે, જે તમારા મલ્ટિ-કોર પ્રોસેસર્સની સંપૂર્ણ સંભાવનાને અનલોક કરે છે. અમે શ્રેષ્ઠ પદ્ધતિઓ, સામાન્ય ભૂલોને આવરી લઈશું અને તમને તમારા પાયથોન એપ્લિકેશન્સને પ્રદર્શન અને સ્કેલેબિલિટી માટે ઓપ્ટિમાઇઝ કરવા માટે જ્ઞાન અને કુશળતાથી સજ્જ કરવા માટે વ્યવહારુ ઉદાહરણો પ્રદાન કરીશું.
મલ્ટિપ્રોસેસિંગની જરૂરિયાતને સમજવી
તકનીકી વિગતોમાં ડૂબકી મારતા પહેલાં, તે સમજવું નિર્ણાયક છે કે શા માટે અમુક પરિસ્થિતિઓમાં મલ્ટિપ્રોસેસિંગ આવશ્યક છે. નીચેની પરિસ્થિતિઓનો વિચાર કરો:
- CPU-બાઉન્ડ કાર્યો: ઓપરેશન્સ જે CPU પ્રોસેસિંગ પર ખૂબ આધાર રાખે છે, જેમ કે ઇમેજ પ્રોસેસિંગ, સંખ્યાત્મક ગણતરીઓ, અથવા જટિલ સિમ્યુલેશન્સ, GIL દ્વારા ગંભીર રીતે મર્યાદિત છે. મલ્ટિપ્રોસેસિંગ આ કાર્યોને બહુવિધ કોરો પર વિતરિત કરવાની મંજૂરી આપે છે, જેનાથી નોંધપાત્ર સ્પીડઅપ્સ પ્રાપ્ત થાય છે.
- મોટા ડેટાસેટ્સ: મોટા ડેટાસેટ્સ સાથે કામ કરતી વખતે, બહુવિધ પ્રક્રિયાઓમાં પ્રોસેસિંગ વર્કલોડનું વિતરણ કરવાથી પ્રોસેસિંગ સમયમાં નાટકીય રીતે ઘટાડો થઈ શકે છે. શેરબજારના ડેટા અથવા જેનોમિક સિક્વન્સનું વિશ્લેષણ કરવાની કલ્પના કરો - મલ્ટિપ્રોસેસિંગ આ કાર્યોને વ્યવસ્થિત બનાવી શકે છે.
- સ્વતંત્ર કાર્યો: જો તમારી એપ્લિકેશનમાં એક સાથે બહુવિધ સ્વતંત્ર કાર્યો ચલાવવાનો સમાવેશ થાય છે, તો મલ્ટિપ્રોસેસિંગ તેમને સમાંતર બનાવવાની એક કુદરતી અને કાર્યક્ષમ રીત પ્રદાન કરે છે. એક વેબ સર્વર વિશે વિચારો જે એક સાથે બહુવિધ ક્લાયંટ વિનંતીઓને હેન્ડલ કરે છે અથવા ડેટા પાઇપલાઇન જે સમાંતર રીતે વિવિધ ડેટા સ્ત્રોતો પર પ્રક્રિયા કરે છે.
જો કે, તે નોંધવું અગત્યનું છે કે મલ્ટિપ્રોસેસિંગ તેની પોતાની જટિલતાઓ રજૂ કરે છે, જેમ કે ઇન્ટર-પ્રોસેસ કોમ્યુનિકેશન (IPC) અને મેમરી મેનેજમેન્ટ. મલ્ટિપ્રોસેસિંગ અને મલ્ટિથ્રેડિંગ વચ્ચેની પસંદગી હાથ પરના કાર્યની પ્રકૃતિ પર ખૂબ આધાર રાખે છે. I/O-બાઉન્ડ કાર્યો (દા.ત., નેટવર્ક વિનંતીઓ, ડિસ્ક I/O) ને ઘણીવાર asyncio જેવી લાઇબ્રેરીઓનો ઉપયોગ કરીને મલ્ટિથ્રેડિંગથી વધુ ફાયદો થાય છે, જ્યારે CPU-બાઉન્ડ કાર્યો સામાન્ય રીતે મલ્ટિપ્રોસેસિંગ માટે વધુ યોગ્ય હોય છે.
પ્રોસેસ પૂલ્સનો પરિચય
પ્રોસેસ પૂલ એ કાર્યકર પ્રક્રિયાઓનો સંગ્રહ છે જે એક સાથે કાર્યો કરવા માટે ઉપલબ્ધ છે. multiprocessing.Pool ક્લાસ આ કાર્યકર પ્રક્રિયાઓનું સંચાલન કરવા અને તેમની વચ્ચે કાર્યોનું વિતરણ કરવાની એક અનુકૂળ રીત પ્રદાન કરે છે. પ્રોસેસ પૂલ્સનો ઉપયોગ વ્યક્તિગત પ્રક્રિયાઓને મેન્યુઅલી મેનેજ કરવાની જરૂરિયાત વિના કાર્યોને સમાંતર કરવાની પ્રક્રિયાને સરળ બનાવે છે.
પ્રોસેસ પૂલ બનાવવું
પ્રોસેસ પૂલ બનાવવા માટે, તમે સામાન્ય રીતે બનાવવાની કાર્યકર પ્રક્રિયાઓની સંખ્યા સ્પષ્ટ કરો છો. જો સંખ્યા ઉલ્લેખિત ન હોય, તો સિસ્ટમમાં CPUs ની સંખ્યા નક્કી કરવા માટે multiprocessing.cpu_count() નો ઉપયોગ કરવામાં આવે છે અને તેટલી પ્રક્રિયાઓ સાથે પૂલ બનાવવામાં આવે છે.
from multiprocessing import Pool, cpu_count
def worker_function(x):
# Perform some computationally intensive task
return x * x
if __name__ == '__main__':
num_processes = cpu_count() # Get the number of CPUs
with Pool(processes=num_processes) as pool:
results = pool.map(worker_function, range(10))
print(results)
સમજૂતી:
- અમે
multiprocessingમોડ્યુલમાંથીPoolક્લાસ અનેcpu_countફંક્શન આયાત કરીએ છીએ. - અમે એક
worker_functionવ્યાખ્યાયિત કરીએ છીએ જે ગણતરીની દ્રષ્ટિએ સઘન કાર્ય કરે છે (આ કિસ્સામાં, સંખ્યાનો વર્ગ કરવો). if __name__ == '__main__':બ્લોકની અંદર (એ સુનિશ્ચિત કરવું કે કોડ ફક્ત ત્યારે જ ચલાવવામાં આવે જ્યારે સ્ક્રિપ્ટ સીધી રીતે ચલાવવામાં આવે), અમેwith Pool(...) as pool:નિવેદનનો ઉપયોગ કરીને પ્રોસેસ પૂલ બનાવીએ છીએ. આ સુનિશ્ચિત કરે છે કે જ્યારે બ્લોકમાંથી બહાર નીકળવામાં આવે ત્યારે પૂલ યોગ્ય રીતે સમાપ્ત થાય છે.- અમે
pool.map()પદ્ધતિનો ઉપયોગworker_functionનેrange(10)ઇટરેબલમાં દરેક ઘટક પર લાગુ કરવા માટે કરીએ છીએ.map()પદ્ધતિ પૂલમાં કાર્યકર પ્રક્રિયાઓ વચ્ચે કાર્યોનું વિતરણ કરે છે અને પરિણામોની સૂચિ પરત કરે છે. - છેલ્લે, અમે પરિણામો છાપીએ છીએ.
map(), apply(), apply_async(), અને imap() પદ્ધતિઓ
Pool ક્લાસ કાર્યકર પ્રક્રિયાઓમાં કાર્યો સબમિટ કરવા માટે ઘણી પદ્ધતિઓ પ્રદાન કરે છે:
map(func, iterable):iterableમાં દરેક આઇટમ પરfuncલાગુ કરે છે, જ્યાં સુધી બધા પરિણામો તૈયાર ન થાય ત્યાં સુધી બ્લોક કરે છે. પરિણામો ઇનપુટ ઇટરેબલ જેવા જ ક્રમમાં સૂચિમાં પરત કરવામાં આવે છે.apply(func, args=(), kwds={}): આપેલ દલીલો સાથેfuncને કૉલ કરે છે. ફંક્શન પૂર્ણ થાય ત્યાં સુધી તે બ્લોક કરે છે અને પરિણામ પરત કરે છે. સામાન્ય રીતે, બહુવિધ કાર્યો માટેapplyએmapકરતાં ઓછું કાર્યક્ષમ છે.apply_async(func, args=(), kwds={}, callback=None, error_callback=None):applyનું નોન-બ્લોકિંગ સંસ્કરણ. તેAsyncResultઓબ્જેક્ટ પરત કરે છે. પરિણામ મેળવવા માટે તમેAsyncResultઓબ્જેક્ટનીget()પદ્ધતિનો ઉપયોગ કરી શકો છો, જે પરિણામ ઉપલબ્ધ ન થાય ત્યાં સુધી બ્લોક કરશે. તે કૉલબેક ફંક્શન્સને પણ સપોર્ટ કરે છે, જે તમને અસુમેળ રીતે પરિણામો પર પ્રક્રિયા કરવાની મંજૂરી આપે છે.error_callbackનો ઉપયોગ ફંક્શન દ્વારા ઉઠાવવામાં આવેલા અપવાદોને હેન્ડલ કરવા માટે કરી શકાય છે.imap(func, iterable, chunksize=1):mapનું એક લેઝી સંસ્કરણ. તે એક ઇટરેટર પરત કરે છે જે પરિણામો ઉપલબ્ધ થતાં જ આપે છે, બધા કાર્યો પૂર્ણ થવાની રાહ જોયા વિના.chunksizeદલીલ દરેક કાર્યકર પ્રક્રિયામાં સબમિટ કરેલા કામના ટુકડાઓનું કદ સ્પષ્ટ કરે છે.imap_unordered(func, iterable, chunksize=1):imapજેવું જ છે, પરંતુ પરિણામોનો ક્રમ ઇનપુટ ઇટરેબલના ક્રમ સાથે મેળ ખાતો હોવાની ખાતરી નથી. જો પરિણામોનો ક્રમ મહત્વપૂર્ણ ન હોય તો આ વધુ કાર્યક્ષમ હોઈ શકે છે.
યોગ્ય પદ્ધતિ પસંદ કરવી તમારી ચોક્કસ જરૂરિયાતો પર આધાર રાખે છે:
- જ્યારે તમને ઇનપુટ ઇટરેબલના સમાન ક્રમમાં પરિણામોની જરૂર હોય અને બધા કાર્યો પૂર્ણ થવાની રાહ જોવા તૈયાર હોવ ત્યારે
mapનો ઉપયોગ કરો. - એક જ કાર્ય માટે અથવા જ્યારે તમારે કીવર્ડ દલીલો પસાર કરવાની જરૂર હોય ત્યારે
applyનો ઉપયોગ કરો. - જ્યારે તમારે અસુમેળ રીતે કાર્યો ચલાવવાની જરૂર હોય અને મુખ્ય પ્રક્રિયાને અવરોધિત કરવા માંગતા ન હોવ ત્યારે
apply_asyncનો ઉપયોગ કરો. - જ્યારે તમારે પરિણામો ઉપલબ્ધ થતાં જ પ્રક્રિયા કરવાની જરૂર હોય અને થોડો ઓવરહેડ સહન કરી શકો ત્યારે
imapનો ઉપયોગ કરો. - જ્યારે પરિણામોનો ક્રમ મહત્વનો ન હોય અને તમે મહત્તમ કાર્યક્ષમતા ઇચ્છતા હોવ ત્યારે
imap_unorderedનો ઉપયોગ કરો.
ઉદાહરણ: કૉલબેક્સ સાથે અસુમેળ કાર્ય સબમિશન
from multiprocessing import Pool, cpu_count
import time
def worker_function(x):
# Simulate a time-consuming task
time.sleep(1)
return x * x
def callback_function(result):
print(f"Result received: {result}")
def error_callback_function(exception):
print(f"An error occurred: {exception}")
if __name__ == '__main__':
num_processes = cpu_count()
with Pool(processes=num_processes) as pool:
for i in range(5):
pool.apply_async(worker_function, args=(i,), callback=callback_function, error_callback=error_callback_function)
# Close the pool and wait for all tasks to complete
pool.close()
pool.join()
print("All tasks completed.")
સમજૂતી:
- અમે એક
callback_functionવ્યાખ્યાયિત કરીએ છીએ જે જ્યારે કોઈ કાર્ય સફળતાપૂર્વક પૂર્ણ થાય ત્યારે કૉલ કરવામાં આવે છે. - અમે એક
error_callback_functionવ્યાખ્યાયિત કરીએ છીએ જે જો કોઈ કાર્ય અપવાદ ઉઠાવે તો કૉલ કરવામાં આવે છે. - અમે પૂલમાં અસુમેળ રીતે કાર્યો સબમિટ કરવા માટે
pool.apply_async()નો ઉપયોગ કરીએ છીએ. - પૂલમાં વધુ કાર્યો સબમિટ થતા અટકાવવા માટે અમે
pool.close()ને કૉલ કરીએ છીએ. - પ્રોગ્રામમાંથી બહાર નીકળતા પહેલા પૂલમાંના બધા કાર્યો પૂર્ણ થવાની રાહ જોવા માટે અમે
pool.join()ને કૉલ કરીએ છીએ.
શેર્ડ મેમરી મેનેજમેન્ટ
જ્યારે પ્રોસેસ પૂલ્સ કાર્યક્ષમ સમાંતર અમલને સક્ષમ કરે છે, ત્યારે પ્રક્રિયાઓ વચ્ચે ડેટા શેર કરવો એક પડકાર બની શકે છે. દરેક પ્રક્રિયાની પોતાની મેમરી સ્પેસ હોય છે, જે અન્ય પ્રક્રિયાઓમાં ડેટાની સીધી ઍક્સેસને અટકાવે છે. પાયથોનનું multiprocessing મોડ્યુલ પ્રક્રિયાઓ વચ્ચે સુરક્ષિત અને કાર્યક્ષમ ડેટા શેરિંગની સુવિધા માટે શેર્ડ મેમરી ઓબ્જેક્ટ્સ અને સિંક્રોનાઇઝેશન પ્રિમિટિવ્સ પ્રદાન કરે છે.
શેર્ડ મેમરી ઓબ્જેક્ટ્સ: Value અને Array
Value અને Array ક્લાસ તમને શેર્ડ મેમરી ઓબ્જેક્ટ્સ બનાવવા દે છે જે બહુવિધ પ્રક્રિયાઓ દ્વારા ઍક્સેસ અને સંશોધિત કરી શકાય છે.
Value(typecode_or_type, *args, lock=True): એક શેર્ડ મેમરી ઓબ્જેક્ટ બનાવે છે જે ઉલ્લેખિત પ્રકારનું એક જ મૂલ્ય ધરાવે છે.typecode_or_typeમૂલ્યનો ડેટા પ્રકાર સ્પષ્ટ કરે છે (દા.ત., પૂર્ણાંક માટે'i', ડબલ માટે'd',ctypes.c_int,ctypes.c_double).lock=Trueરેસની પરિસ્થિતિઓને રોકવા માટે સંકળાયેલ લોક બનાવે છે.Array(typecode_or_type, sequence, lock=True): એક શેર્ડ મેમરી ઓબ્જેક્ટ બનાવે છે જે ઉલ્લેખિત પ્રકારના મૂલ્યોનો એરે ધરાવે છે.typecode_or_typeએરે તત્વોનો ડેટા પ્રકાર સ્પષ્ટ કરે છે (દા.ત., પૂર્ણાંક માટે'i', ડબલ માટે'd',ctypes.c_int,ctypes.c_double).sequenceએ એરે માટે મૂલ્યોનો પ્રારંભિક ક્રમ છે.lock=Trueરેસની પરિસ્થિતિઓને રોકવા માટે સંકળાયેલ લોક બનાવે છે.
ઉદાહરણ: પ્રક્રિયાઓ વચ્ચે મૂલ્ય શેર કરવું
from multiprocessing import Process, Value, Lock
import time
def increment_value(shared_value, lock, num_increments):
for _ in range(num_increments):
with lock:
shared_value.value += 1
time.sleep(0.01) # Simulate some work
if __name__ == '__main__':
shared_value = Value('i', 0) # Create a shared integer with initial value 0
lock = Lock() # Create a lock for synchronization
num_processes = 3
num_increments = 100
processes = []
for _ in range(num_processes):
p = Process(target=increment_value, args=(shared_value, lock, num_increments))
processes.append(p)
p.start()
for p in processes:
p.join()
print(f"Final value: {shared_value.value}")
સમજૂતી:
- અમે 0 ના પ્રારંભિક મૂલ્ય સાથે પૂર્ણાંક પ્રકાર (
'i') નો શેર્ડValueઓબ્જેક્ટ બનાવીએ છીએ. - શેર્ડ મૂલ્યની ઍક્સેસને સિંક્રનાઇઝ કરવા માટે અમે એક
Lockઓબ્જેક્ટ બનાવીએ છીએ. - અમે બહુવિધ પ્રક્રિયાઓ બનાવીએ છીએ, જેમાંથી દરેક શેર્ડ મૂલ્યને ચોક્કસ સંખ્યામાં વધારો કરે છે.
increment_valueફંક્શનની અંદર, અમે શેર્ડ મૂલ્યને ઍક્સેસ કરતા પહેલા લોક મેળવવા અને પછી તેને છોડવા માટેwith lock:નિવેદનનો ઉપયોગ કરીએ છીએ. આ સુનિશ્ચિત કરે છે કે એક સમયે માત્ર એક જ પ્રક્રિયા શેર્ડ મૂલ્યને ઍક્સેસ કરી શકે છે, જે રેસની પરિસ્થિતિઓને અટકાવે છે.- બધી પ્રક્રિયાઓ પૂર્ણ થયા પછી, અમે શેર્ડ વેરિયેબલનું અંતિમ મૂલ્ય છાપીએ છીએ. લોક વિના, રેસની પરિસ્થિતિઓને કારણે અંતિમ મૂલ્ય અણધારી હશે.
ઉદાહરણ: પ્રક્રિયાઓ વચ્ચે એરે શેર કરવું
from multiprocessing import Process, Array
import random
def fill_array(shared_array):
for i in range(len(shared_array)):
shared_array[i] = random.random()
if __name__ == '__main__':
array_size = 10
shared_array = Array('d', array_size) # Create a shared array of doubles
processes = []
for _ in range(3):
p = Process(target=fill_array, args=(shared_array,))
processes.append(p)
p.start()
for p in processes:
p.join()
print(f"Final array: {list(shared_array)}")
સમજૂતી:
- અમે ઉલ્લેખિત કદ સાથે ડબલ પ્રકાર (
'd') નો શેર્ડArrayઓબ્જેક્ટ બનાવીએ છીએ. - અમે બહુવિધ પ્રક્રિયાઓ બનાવીએ છીએ, જેમાંથી દરેક એરેને રેન્ડમ નંબરોથી ભરે છે.
- બધી પ્રક્રિયાઓ પૂર્ણ થયા પછી, અમે શેર્ડ એરેની સામગ્રી છાપીએ છીએ. નોંધ કરો કે દરેક પ્રક્રિયા દ્વારા કરવામાં આવેલા ફેરફારો શેર્ડ એરેમાં પ્રતિબિંબિત થાય છે.
સિંક્રોનાઇઝેશન પ્રિમિટિવ્સ: લોક્સ, સેમાફોર્સ, અને કન્ડિશન્સ
જ્યારે બહુવિધ પ્રક્રિયાઓ શેર્ડ મેમરીને ઍક્સેસ કરે છે, ત્યારે રેસની પરિસ્થિતિઓને રોકવા અને ડેટાની સુસંગતતા સુનિશ્ચિત કરવા માટે સિંક્રોનાઇઝેશન પ્રિમિટિવ્સનો ઉપયોગ કરવો આવશ્યક છે. multiprocessing મોડ્યુલ ઘણા સિંક્રોનાઇઝેશન પ્રિમિટિવ્સ પ્રદાન કરે છે, જેમાં શામેલ છે:
Lock: એક મૂળભૂત લોકિંગ મિકેનિઝમ જે એક સમયે માત્ર એક જ પ્રક્રિયાને લોક મેળવવાની મંજૂરી આપે છે. શેર્ડ સંસાધનોને ઍક્સેસ કરતા કોડના નિર્ણાયક વિભાગોને સુરક્ષિત કરવા માટે વપરાય છે.Semaphore: એક વધુ સામાન્ય સિંક્રોનાઇઝેશન પ્રિમિટિવ જે મર્યાદિત સંખ્યામાં પ્રક્રિયાઓને એક સાથે શેર્ડ સંસાધનને ઍક્સેસ કરવાની મંજૂરી આપે છે. મર્યાદિત ક્ષમતાવાળા સંસાધનોની ઍક્સેસને નિયંત્રિત કરવા માટે ઉપયોગી છે.Condition: એક સિંક્રોનાઇઝેશન પ્રિમિટિવ જે પ્રક્રિયાઓને કોઈ ચોક્કસ શરત સાચી થવાની રાહ જોવાની મંજૂરી આપે છે. ઘણીવાર ઉત્પાદક-ગ્રાહક પરિદ્રશ્યોમાં વપરાય છે.
અમે પહેલાથી જ શેર્ડ Value ઓબ્જેક્ટ્સ સાથે Lock નો ઉપયોગ કરવાનું ઉદાહરણ જોયું છે. ચાલો Condition નો ઉપયોગ કરીને એક સરળ ઉત્પાદક-ગ્રાહક પરિદ્રશ્યની તપાસ કરીએ.
ઉદાહરણ: કન્ડિશન સાથે ઉત્પાદક-ગ્રાહક
from multiprocessing import Process, Condition, Queue
import time
import random
def producer(condition, queue):
for i in range(5):
time.sleep(random.random())
condition.acquire()
queue.put(i)
print(f"Produced: {i}")
condition.notify()
condition.release()
def consumer(condition, queue):
for _ in range(5):
condition.acquire()
while queue.empty():
print("Consumer waiting...")
condition.wait()
item = queue.get()
print(f"Consumed: {item}")
condition.release()
if __name__ == '__main__':
condition = Condition()
queue = Queue()
p = Process(target=producer, args=(condition, queue))
c = Process(target=consumer, args=(condition, queue))
p.start()
c.start()
p.join()
c.join()
print("Done.")
સમજૂતી:
- ડેટાના ઇન્ટર-પ્રોસેસ કોમ્યુનિકેશન માટે
Queueનો ઉપયોગ થાય છે. - ઉત્પાદક અને ગ્રાહકને સિંક્રનાઇઝ કરવા માટે
Conditionનો ઉપયોગ થાય છે. ગ્રાહક કતારમાં ડેટા ઉપલબ્ધ થવાની રાહ જુએ છે, અને ઉત્પાદક ડેટા ઉત્પન્ન થાય ત્યારે ગ્રાહકને સૂચિત કરે છે. condition.acquire()અનેcondition.release()પદ્ધતિઓનો ઉપયોગ કન્ડિશન સાથે સંકળાયેલ લોક મેળવવા અને છોડવા માટે થાય છે.condition.wait()પદ્ધતિ લોક છોડે છે અને સૂચનાની રાહ જુએ છે.condition.notify()પદ્ધતિ એક રાહ જોતા થ્રેડ (અથવા પ્રક્રિયા) ને સૂચિત કરે છે કે શરત સાચી હોઈ શકે છે.
વૈશ્વિક પ્રેક્ષકો માટે વિચારણાઓ
વૈશ્વિક પ્રેક્ષકો માટે મલ્ટિપ્રોસેસિંગ એપ્લિકેશન્સ વિકસાવતી વખતે, વિવિધ વાતાવરણમાં સુસંગતતા અને શ્રેષ્ઠ પ્રદર્શન સુનિશ્ચિત કરવા માટે વિવિધ પરિબળો ધ્યાનમાં લેવા આવશ્યક છે:
- કેરેક્ટર એન્કોડિંગ: પ્રક્રિયાઓ વચ્ચે સ્ટ્રિંગ્સ શેર કરતી વખતે કેરેક્ટર એન્કોડિંગનું ધ્યાન રાખો. UTF-8 સામાન્ય રીતે એક સુરક્ષિત અને વ્યાપકપણે સમર્થિત એન્કોડિંગ છે. ખોટું એન્કોડિંગ વિવિધ ભાષાઓ સાથે કામ કરતી વખતે ગરબડ ટેક્સ્ટ અથવા ભૂલો તરફ દોરી શકે છે.
- લોકેલ સેટિંગ્સ: લોકેલ સેટિંગ્સ અમુક ફંક્શન્સના વર્તનને અસર કરી શકે છે, જેમ કે તારીખ અને સમય ફોર્મેટિંગ. લોકેલ-વિશિષ્ટ કામગીરીને યોગ્ય રીતે હેન્ડલ કરવા માટે
localeમોડ્યુલનો ઉપયોગ કરવાનું વિચારો. - સમય ઝોન: સમય-સંવેદનશીલ ડેટા સાથે કામ કરતી વખતે, સમય ઝોન વિશે જાગૃત રહો અને સમય ઝોન રૂપાંતરણોને ચોક્કસ રીતે હેન્ડલ કરવા માટે
pytzલાઇબ્રેરી સાથેdatetimeમોડ્યુલનો ઉપયોગ કરો. આ એવા એપ્લિકેશન્સ માટે નિર્ણાયક છે જે વિવિધ ભૌગોલિક પ્રદેશોમાં કાર્ય કરે છે. - સંસાધન મર્યાદાઓ: ઓપરેટિંગ સિસ્ટમ્સ પ્રક્રિયાઓ પર સંસાધન મર્યાદાઓ લાદી શકે છે, જેમ કે મેમરી વપરાશ અથવા ખુલ્લી ફાઇલોની સંખ્યા. આ મર્યાદાઓ વિશે જાગૃત રહો અને તે મુજબ તમારી એપ્લિકેશન ડિઝાઇન કરો. વિવિધ ઓપરેટિંગ સિસ્ટમ્સ અને હોસ્ટિંગ વાતાવરણમાં વિવિધ ડિફોલ્ટ મર્યાદાઓ હોય છે.
- પ્લેટફોર્મ સુસંગતતા: જ્યારે પાયથોનનું
multiprocessingમોડ્યુલ પ્લેટફોર્મ-સ્વતંત્ર બનવા માટે રચાયેલ છે, ત્યારે વિવિધ ઓપરેટિંગ સિસ્ટમ્સ (વિન્ડોઝ, મેકઓએસ, લિનક્સ) માં વર્તનમાં સૂક્ષ્મ તફાવત હોઈ શકે છે. બધા લક્ષ્ય પ્લેટફોર્મ્સ પર તમારી એપ્લિકેશનનું સંપૂર્ણ પરીક્ષણ કરો. ઉદાહરણ તરીકે, જે રીતે પ્રક્રિયાઓ બનાવવામાં આવે છે તે અલગ હોઈ શકે છે (ફોર્કિંગ વિ. સ્પાવનિંગ). - ભૂલ હેન્ડલિંગ અને લોગિંગ: વિવિધ વાતાવરણમાં ઊભી થઈ શકે તેવી સમસ્યાઓનું નિદાન અને નિરાકરણ કરવા માટે મજબૂત ભૂલ હેન્ડલિંગ અને લોગિંગનો અમલ કરો. લોગ સંદેશા સ્પષ્ટ, માહિતીપ્રદ અને સંભવિતપણે અનુવાદયોગ્ય હોવા જોઈએ. સરળ ડિબગીંગ માટે કેન્દ્રિય લોગિંગ સિસ્ટમનો ઉપયોગ કરવાનું વિચારો.
- આંતરરાષ્ટ્રીયકરણ (i18n) અને સ્થાનિકીકરણ (l10n): જો તમારી એપ્લિકેશનમાં યુઝર ઇન્ટરફેસ અથવા ટેક્સ્ટ પ્રદર્શિત થાય છે, તો બહુવિધ ભાષાઓ અને સાંસ્કૃતિક પસંદગીઓને સમર્થન આપવા માટે આંતરરાષ્ટ્રીયકરણ અને સ્થાનિકીકરણનો વિચાર કરો. આમાં સ્ટ્રિંગ્સને બાહ્ય બનાવવાનો અને વિવિધ લોકેલ માટે અનુવાદ પ્રદાન કરવાનો સમાવેશ થઈ શકે છે.
મલ્ટિપ્રોસેસિંગ માટે શ્રેષ્ઠ પદ્ધતિઓ
મલ્ટિપ્રોસેસિંગના લાભોને મહત્તમ કરવા અને સામાન્ય ભૂલોથી બચવા માટે, આ શ્રેષ્ઠ પદ્ધતિઓનું પાલન કરો:
- કાર્યોને સ્વતંત્ર રાખો: શેર્ડ મેમરી અને સિંક્રોનાઇઝેશનની જરૂરિયાતને ઘટાડવા માટે તમારા કાર્યોને શક્ય તેટલા સ્વતંત્ર બનાવવા માટે ડિઝાઇન કરો. આ રેસની પરિસ્થિતિઓ અને સંઘર્ષનું જોખમ ઘટાડે છે.
- ડેટા ટ્રાન્સફર ઓછું કરો: ઓવરહેડ ઘટાડવા માટે પ્રક્રિયાઓ વચ્ચે ફક્ત જરૂરી ડેટા ટ્રાન્સફર કરો. જો શક્ય હોય તો મોટા ડેટા સ્ટ્રક્ચર્સ શેર કરવાનું ટાળો. ખૂબ મોટા ડેટાસેટ્સ માટે ઝીરો-કોપી શેરિંગ અથવા મેમરી મેપિંગ જેવી તકનીકોનો ઉપયોગ કરવાનું વિચારો.
- લોક્સનો ઓછો ઉપયોગ કરો: લોક્સનો વધુ પડતો ઉપયોગ પ્રદર્શનની સમસ્યાઓ તરફ દોરી શકે છે. કોડના નિર્ણાયક વિભાગોને સુરક્ષિત કરવા માટે ફક્ત જરૂરી હોય ત્યારે જ લોક્સનો ઉપયોગ કરો. જો યોગ્ય હોય તો, સેમાફોર્સ અથવા કન્ડિશન્સ જેવા વૈકલ્પિક સિંક્રોનાઇઝેશન પ્રિમિટિવ્સનો ઉપયોગ કરવાનું વિચારો.
- ડેડલોક્સ ટાળો: ડેડલોક્સ ટાળવા માટે સાવચેત રહો, જે ત્યારે થઈ શકે છે જ્યારે બે કે તેથી વધુ પ્રક્રિયાઓ અનિશ્ચિત સમય માટે અવરોધિત હોય, એકબીજાના સંસાધનો છોડવાની રાહ જોતી હોય. ડેડલોક્સને રોકવા માટે સુસંગત લોકિંગ ઓર્ડરનો ઉપયોગ કરો.
- અપવાદોને યોગ્ય રીતે હેન્ડલ કરો: કાર્યકર પ્રક્રિયાઓમાં અપવાદોને હેન્ડલ કરો જેથી તેઓ ક્રેશ થતા અને સંભવિતપણે સમગ્ર એપ્લિકેશનને બંધ કરતા અટકાવી શકાય. અપવાદોને પકડવા અને તેમને યોગ્ય રીતે લોગ કરવા માટે ટ્રાય-એક્સેપ્ટ બ્લોક્સનો ઉપયોગ કરો.
- સંસાધન વપરાશનું નિરીક્ષણ કરો: સંભવિત અવરોધો અથવા પ્રદર્શન સમસ્યાઓને ઓળખવા માટે તમારી મલ્ટિપ્રોસેસિંગ એપ્લિકેશનના સંસાધન વપરાશનું નિરીક્ષણ કરો. CPU વપરાશ, મેમરી વપરાશ અને I/O પ્રવૃત્તિનું નિરીક્ષણ કરવા માટે
psutilજેવા સાધનોનો ઉપયોગ કરો. - ટાસ્ક ક્યુનો ઉપયોગ કરવાનું વિચારો: વધુ જટિલ પરિદ્રશ્યો માટે, કાર્યોનું સંચાલન કરવા અને તેમને બહુવિધ પ્રક્રિયાઓ અથવા તો બહુવિધ મશીનો પર વિતરિત કરવા માટે ટાસ્ક ક્યુ (દા.ત., સેલરી, રેડિસ ક્યુ) નો ઉપયોગ કરવાનું વિચારો. ટાસ્ક ક્યુઝ ટાસ્ક પ્રાથમિકતા, પુન:પ્રયાસ મિકેનિઝમ્સ અને મોનિટરિંગ જેવી સુવિધાઓ પ્રદાન કરે છે.
- તમારા કોડને પ્રોફાઇલ કરો: તમારા કોડના સૌથી વધુ સમય લેતા ભાગોને ઓળખવા માટે પ્રોફાઇલરનો ઉપયોગ કરો અને તે વિસ્તારો પર તમારા ઓપ્ટિમાઇઝેશન પ્રયત્નોને કેન્દ્રિત કરો. પાયથોન
cProfileઅનેline_profilerજેવા ઘણા પ્રોફાઇલિંગ સાધનો પ્રદાન કરે છે. - સંપૂર્ણ પરીક્ષણ કરો: તમારી મલ્ટિપ્રોસેસિંગ એપ્લિકેશન યોગ્ય રીતે અને કાર્યક્ષમ રીતે કામ કરી રહી છે તેની ખાતરી કરવા માટે તેનું સંપૂર્ણ પરીક્ષણ કરો. વ્યક્તિગત ઘટકોની શુદ્ધતા ચકાસવા માટે યુનિટ પરીક્ષણોનો ઉપયોગ કરો અને વિવિધ પ્રક્રિયાઓ વચ્ચેની ક્રિયાપ્રતિક્રિયા ચકાસવા માટે ઇન્ટિગ્રેશન પરીક્ષણોનો ઉપયોગ કરો.
- તમારા કોડનું દસ્તાવેજીકરણ કરો: તમારા કોડનું સ્પષ્ટપણે દસ્તાવેજીકરણ કરો, જેમાં દરેક પ્રક્રિયાનો હેતુ, ઉપયોગમાં લેવાતા શેર્ડ મેમરી ઓબ્જેક્ટ્સ અને નિયોજિત સિંક્રોનાઇઝેશન મિકેનિઝમ્સનો સમાવેશ થાય છે. આ અન્ય લોકો માટે તમારા કોડને સમજવા અને જાળવવાનું સરળ બનાવશે.
અદ્યતન તકનીકો અને વિકલ્પો
પ્રોસેસ પૂલ્સ અને શેર્ડ મેમરીના મૂળભૂત સિદ્ધાંતો ઉપરાંત, વધુ જટિલ મલ્ટિપ્રોસેસિંગ પરિદ્રશ્યો માટે ધ્યાનમાં લેવા માટે ઘણી અદ્યતન તકનીકો અને વૈકલ્પિક અભિગમો છે:
- ZeroMQ: એક ઉચ્ચ-પ્રદર્શન અસુમેળ મેસેજિંગ લાઇબ્રેરી જેનો ઉપયોગ ઇન્ટર-પ્રોસેસ કોમ્યુનિકેશન માટે કરી શકાય છે. ZeroMQ વિવિધ મેસેજિંગ પેટર્ન પ્રદાન કરે છે, જેમ કે પબ્લિશ-સબ્સ્ક્રાઇબ, રિક્વેસ્ટ-રિપ્લાય, અને પુશ-પુલ.
- Redis: એક ઇન-મેમરી ડેટા સ્ટ્રક્ચર સ્ટોર જેનો ઉપયોગ શેર્ડ મેમરી અને ઇન્ટર-પ્રોસેસ કોમ્યુનિકેશન માટે કરી શકાય છે. Redis પબ/સબ, ટ્રાન્ઝેક્શન્સ અને સ્ક્રિપ્ટીંગ જેવી સુવિધાઓ પ્રદાન કરે છે.
- Dask: એક સમાંતર કમ્પ્યુટિંગ લાઇબ્રેરી જે મોટા ડેટાસેટ્સ પર ગણતરીઓને સમાંતર કરવા માટે ઉચ્ચ-સ્તરનું ઇન્ટરફેસ પ્રદાન કરે છે. Dask નો ઉપયોગ પ્રોસેસ પૂલ્સ અથવા વિતરિત ક્લસ્ટરો સાથે કરી શકાય છે.
- Ray: એક વિતરિત એક્ઝેક્યુશન ફ્રેમવર્ક જે AI અને પાયથોન એપ્લિકેશન્સ બનાવવા અને સ્કેલ કરવાનું સરળ બનાવે છે. Ray રિમોટ ફંક્શન કોલ્સ, વિતરિત એક્ટર્સ અને સ્વચાલિત ડેટા મેનેજમેન્ટ જેવી સુવિધાઓ પ્રદાન કરે છે.
- MPI (Message Passing Interface): ઇન્ટર-પ્રોસેસ કોમ્યુનિકેશન માટેનું એક ધોરણ, જે સામાન્ય રીતે વૈજ્ઞાનિક કમ્પ્યુટિંગમાં વપરાય છે. પાયથોનમાં MPI માટે બાઇન્ડિંગ્સ છે, જેમ કે
mpi4py. - શેર્ડ મેમરી ફાઇલ્સ (mmap): મેમરી મેપિંગ તમને ફાઇલને મેમરીમાં મેપ કરવાની મંજૂરી આપે છે, જેનાથી બહુવિધ પ્રક્રિયાઓ સમાન ફાઇલ ડેટાને સીધી રીતે ઍક્સેસ કરી શકે છે. આ પરંપરાગત ફાઇલ I/O દ્વારા ડેટા વાંચવા અને લખવા કરતાં વધુ કાર્યક્ષમ હોઈ શકે છે. પાયથોનમાં
mmapમોડ્યુલ મેમરી મેપિંગ માટે સપોર્ટ પૂરો પાડે છે. - અન્ય ભાષાઓમાં પ્રોસેસ-આધારિત વિ. થ્રેડ-આધારિત કોન્કરન્સી: જ્યારે આ માર્ગદર્શિકા પાયથોન પર ધ્યાન કેન્દ્રિત કરે છે, ત્યારે અન્ય ભાષાઓમાં કોન્કરન્સી મોડલ્સને સમજવાથી મૂલ્યવાન આંતરદૃષ્ટિ મળી શકે છે. ઉદાહરણ તરીકે, Go ગોરુટિન્સ (હલકા થ્રેડો) અને ચેનલોનો ઉપયોગ કરે છે, જ્યારે જાવા થ્રેડો અને પ્રોસેસ-આધારિત સમાંતરવાદ બંને પ્રદાન કરે છે.
નિષ્કર્ષ
પાયથોનનું multiprocessing મોડ્યુલ CPU-બાઉન્ડ કાર્યોને સમાંતર કરવા અને પ્રક્રિયાઓ વચ્ચે શેર્ડ મેમરીનું સંચાલન કરવા માટે શક્તિશાળી સાધનોનો સમૂહ પ્રદાન કરે છે. પ્રોસેસ પૂલ્સ, શેર્ડ મેમરી ઓબ્જેક્ટ્સ અને સિંક્રોનાઇઝેશન પ્રિમિટિવ્સના ખ્યાલોને સમજીને, તમે તમારા મલ્ટિ-કોર પ્રોસેસર્સની સંપૂર્ણ સંભાવનાને અનલોક કરી શકો છો અને તમારા પાયથોન એપ્લિકેશન્સના પ્રદર્શનમાં નોંધપાત્ર સુધારો કરી શકો છો.
મલ્ટિપ્રોસેસિંગમાં સામેલ સમાધાનો, જેમ કે ઇન્ટર-પ્રોસેસ કોમ્યુનિકેશનનો ઓવરહેડ અને શેર્ડ મેમરીના સંચાલનની જટિલતા, કાળજીપૂર્વક ધ્યાનમાં લેવાનું યાદ રાખો. શ્રેષ્ઠ પદ્ધતિઓનું પાલન કરીને અને તમારી ચોક્કસ જરૂરિયાતો માટે યોગ્ય તકનીકો પસંદ કરીને, તમે વૈશ્વિક પ્રેક્ષકો માટે કાર્યક્ષમ અને સ્કેલેબલ મલ્ટિપ્રોસેસિંગ એપ્લિકેશન્સ બનાવી શકો છો. સંપૂર્ણ પરીક્ષણ અને મજબૂત ભૂલ હેન્ડલિંગ સર્વોપરી છે, ખાસ કરીને જ્યારે એવી એપ્લિકેશન્સ જમાવવામાં આવે જેમને વિશ્વભરના વિવિધ વાતાવરણમાં વિશ્વસનીય રીતે ચલાવવાની જરૂર હોય.