अजगर में पृष्ठभूमि समारोह


89

मुझे एक पायथन स्क्रिप्ट मिली है जो कभी-कभी उपयोगकर्ता को चित्र दिखाती है। छवियां, कई बार, काफी बड़ी हो सकती हैं, और उनका अक्सर उपयोग किया जाता है। उन्हें प्रदर्शित करना महत्वपूर्ण नहीं है, लेकिन उनके साथ जुड़े संदेश को प्रदर्शित करना है। मुझे एक फ़ंक्शन मिला है जो आवश्यक छवि को डाउनलोड करता है और इसे स्थानीय रूप से बचाता है। अभी यह उस कोड के साथ इनलाइन चलाया जाता है जो उपयोगकर्ता को एक संदेश प्रदर्शित करता है, लेकिन यह कभी-कभी गैर-स्थानीय छवियों के लिए 10 सेकंड से अधिक समय ले सकता है। क्या कोई ऐसा तरीका है जिसे मैं ज़रूरत पड़ने पर इस फ़ंक्शन को कॉल कर सकता हूं, लेकिन कोड निष्पादित करने के लिए पृष्ठभूमि में इसे चलाते रहें? मैं बस एक डिफ़ॉल्ट छवि का उपयोग करूंगा जब तक कि सही उपलब्ध न हो जाए।

जवाबों:


130

कुछ इस तरह से करें:

def function_that_downloads(my_args):
    # do some long download here

फिर इनलाइन, कुछ इस तरह से करें:

import threading
def my_inline_function(some_args):
    # do some stuff
    download_thread = threading.Thread(target=function_that_downloads, name="Downloader", args=some_args)
    download_thread.start()
    # continue doing stuff

आप कॉल करके अन्य चीजों पर जाने से पहले यह देखना चाहते हैं कि धागा समाप्त हो गया है या नहीं download_thread.isAlive()


थ्रेड बंद होने तक दुभाषिया खुला रहता है। (उदाहरण import threading, time; wait=lambda: time.sleep(2); t=threading.Thread(target=wait); t.start(); print('end'))। मैं उम्मीद कर रहा था "पृष्ठभूमि" के रूप में अच्छी तरह से अलग अलग निहित है।
थोरसुमोनर

3
@ थोरसुमोनर थ्रेड्स एक ही प्रक्रिया के भीतर निहित हैं। आप एक नई प्रक्रिया अंडे देने के लिए देख रहे हैं, तो आप इस पर गौर करना चाहते हैं subprocessया multiprocessingबजाय अजगर मॉड्यूल।
TorelTwiddler

@TorelTwiddler मैं पृष्ठभूमि में एक फ़ंक्शन चलाना चाहता हूं, लेकिन मेरी कुछ संसाधन सीमाएं हैं और मैं फ़ंक्शन को कई बार नहीं चला सकता हूं जो मैं चाहता हूं और फ़ंक्शन के अतिरिक्त निष्पादन को पंक्तिबद्ध करना चाहता हूं। क्या आपके पास कोई विचार है कि मुझे यह कैसे करना चाहिए? मेरा सवाल यहाँ है । क्या आप कृपया मेरे प्रश्न पर एक नज़र डाल सकते हैं? कोई भी मदद बहुत अच्छी रहेगी!
अमीर

3
यदि आप कई पैरामीटर चाहते हैं: download_thread = thread.Thread (target = function_that_downloads, args = (variable1, variable2, variableN))
georgeos

कैसे कई args पास करने के लिए - विधि की तरह है add(a,b)और उस विधि का रिटर्न मान प्राप्त करें
Maifee Ul Asad

7

आमतौर पर ऐसा करने का तरीका थ्रेड पूल और कतार डाउनलोड का उपयोग करना होगा जो एक संकेत जारी करेगा, एक घटना, उर्फ ​​एक घटना, जब उस कार्य ने प्रसंस्करण समाप्त कर दिया है। आप ऐसा कर सकते हैं थ्रेडिंग मॉड्यूल के दायरे में पायथन प्रदान करता है।

उक्त कार्यों को करने के लिए, मैं इवेंट ऑब्जेक्ट्स और क्यू मॉड्यूल का उपयोग करूंगा ।

हालाँकि, एक सरल threading.Threadकार्यान्वयन का उपयोग करके आप जो कर सकते हैं उसका एक त्वरित और गंदा प्रदर्शन नीचे देखा जा सकता है:

import os
import threading
import time
import urllib2


class ImageDownloader(threading.Thread):

    def __init__(self, function_that_downloads):
        threading.Thread.__init__(self)
        self.runnable = function_that_downloads
        self.daemon = True

    def run(self):
        self.runnable()


def downloads():
    with open('somefile.html', 'w+') as f:
        try:
            f.write(urllib2.urlopen('http://google.com').read())
        except urllib2.HTTPError:
            f.write('sorry no dice')


print 'hi there user'
print 'how are you today?'
thread = ImageDownloader(downloads)
thread.start()
while not os.path.exists('somefile.html'):
    print 'i am executing but the thread has started to download'
    time.sleep(1)

print 'look ma, thread is not alive: ', thread.is_alive()

यह शायद समझ में नहीं आता है कि मैं चुनाव नहीं कर रहा हूं जैसा कि मैं ऊपर कर रहा हूं। किस स्थिति में, मैं इस कोड को बदलूंगा:

import os
import threading
import time
import urllib2


class ImageDownloader(threading.Thread):

    def __init__(self, function_that_downloads):
        threading.Thread.__init__(self)
        self.runnable = function_that_downloads

    def run(self):
        self.runnable()


def downloads():
    with open('somefile.html', 'w+') as f:
        try:
            f.write(urllib2.urlopen('http://google.com').read())
        except urllib2.HTTPError:
            f.write('sorry no dice')


print 'hi there user'
print 'how are you today?'
thread = ImageDownloader(downloads)
thread.start()
# show message
thread.join()
# display image

ध्यान दें कि यहां कोई डेमॉन फ्लैग सेट नहीं है।


4

मैं इस तरह की चीज के लिए जियोवेंट का उपयोग करना पसंद करता हूं :

import gevent
from gevent import monkey; monkey.patch_all()

greenlet = gevent.spawn( function_to_download_image )
display_message()
# ... perhaps interaction with the user here

# this will wait for the operation to complete (optional)
greenlet.join()
# alternatively if the image display is no longer important, this will abort it:
#greenlet.kill()

सब कुछ एक धागे में चलता है, लेकिन जब भी कोई कर्नेल ऑपरेशन ब्लॉक करता है, तो जब दूसरे "ग्रीनलेट्स" चल रहे होते हैं तो जियोवेंट कॉन्टेक्ट्स को स्विच करता है। लॉकिंग, आदि के बारे में चिंताएं बहुत कम हो जाती हैं, क्योंकि एक समय में केवल एक ही चीज चल रही है, फिर भी "मुख्य" संदर्भ में ब्लॉकिंग ऑपरेशन निष्पादित होने पर छवि डाउनलोड होती रहेगी।

इस बात पर निर्भर करता है कि आप पृष्ठभूमि में कितना और किस तरह का काम करना चाहते हैं, यह थ्रेडिंग आधारित समाधानों से बेहतर या बुरा हो सकता है; निश्चित रूप से, यह बहुत अधिक मापनीय है (यानी आप पृष्ठभूमि में कई और चीजें कर सकते हैं), लेकिन वर्तमान स्थिति में यह चिंता का विषय नहीं हो सकता है।


इस लाइन का उद्देश्य क्या है from gevent import monkey; monkey.patch_all():?
nz_21

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.