Python'da arka plan işlevi


89

Bazen kullanıcıya resim gösteren bir Python komut dizim var. Görüntüler bazen oldukça büyük olabilir ve sıklıkla yeniden kullanılırlar. Bunları görüntülemek kritik değildir, ancak bunlarla ilişkili mesajı görüntülemek önemlidir. Gerekli görüntüyü indiren ve yerel olarak kaydeden bir işlevim var. Şu anda, kullanıcıya bir mesaj görüntüleyen kodla aynı hizada çalışıyor, ancak bu bazen yerel olmayan görüntüler için 10 saniyeden fazla sürebilir. Gerektiğinde bu işlevi çağırabilmemin bir yolu var mı, ancak kod yürütülmeye devam ederken arka planda çalıştırabilir miyim? Doğru olan mevcut olana kadar sadece varsayılan bir resim kullanırdım.

Yanıtlar:


130

Bunun gibi bir şey yapın:

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

sonra satır içi, şuna benzer bir şey yapın:

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

Başka şeylere geçmeden önce iş parçacığının bitip bitmediğini kontrol etmek isteyebilirsiniz. download_thread.isAlive()


Yorumlayıcı, iş parçacığı kapanana kadar açık kalır. (örnek import threading, time; wait=lambda: time.sleep(2); t=threading.Thread(target=wait); t.start(); print('end')). Ben de "arka plan" ın ima edildiğini umuyordum.
ThorSummoner

3
@ThorSummoner Konuların tümü aynı süreç içinde yer alır. Yeni bir süreç oluşturmak istiyorsanız, bunun yerine subprocessveya multiprocessingpython modüllerine bakmak isteyeceksiniz .
TorelTwiddler

@TorelTwiddler Arka planda bir işlevi çalıştırmak istiyorum, ancak bazı kaynak sınırlamalarım var ve işlevi istediğim kadar çalıştıramıyorum ve işlevin fazladan yürütmelerini sıraya koymak istiyorum. Bunu nasıl yapmam gerektiğine dair bir fikrin var mı? Benim sorum var . Soruma bir bakar mısınız lütfen? Herhangi bir yardım harika olur!
Amir

3
Birden fazla parametre istiyorsanız: download_thread = threading.Thread (hedef = function_that_downloads, args = (değişken1, değişken2, değişkenN))
georgeos

birden çok bağımsız değişkenin nasıl geçirileceği - yöntemin olduğu gibi add(a,b)ve bu yöntemin dönüş değerini elde etme gibi
Maifee Ul Asad

7

Tipik olarak bunu yapmanın yolu, görevin işlenmesi bittiğinde bir sinyal, diğer adıyla olay, gönderen bir iş parçacığı havuzu ve kuyruk indirmeleri kullanmaktır. Bunu Python'un sağladığı iş parçacığı modülü kapsamında yapabilirsiniz .

Söz konusu eylemleri gerçekleştirmek için olay nesnelerini ve Kuyruk modülünü kullanırdım .

Bununla birlikte, basit bir threading.Threaduygulama kullanarak neler yapabileceğinizi hızlı ve kirli bir şekilde aşağıda görebilirsiniz:

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()

Yukarıda yaptığım gibi anket yapmamak muhtemelen mantıklı olacaktır. Bu durumda, kodu şu şekilde değiştirirdim:

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

Burada ayarlanmış hiçbir arka plan programı bayrağı olmadığına dikkat edin.


4

Bu tür şeyler için gevent kullanmayı tercih ederim :

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()

Her şey tek bir evrede çalışır, ancak bir çekirdek işlemi engellendiğinde, gevent başka "yeşillikler" çalışırken bağlamları değiştirir. Her seferinde çalışan tek bir şey olduğu için kilitleme vb. İle ilgili endişeler çok azalır, ancak "ana" bağlamda bir engelleme işlemi yürütüldüğünde görüntü indirilmeye devam eder.

Arka planda ne kadar ve ne tür bir şey yapmak istediğinize bağlı olarak, bu iş parçacığı tabanlı çözümlerden daha iyi veya daha kötü olabilir; kesinlikle, çok daha ölçeklenebilir (yani arka planda çok daha fazla şey yapabilirsiniz), ancak mevcut durumda bu endişe verici olmayabilir.


Bu hattın amacı ne: from gevent import monkey; monkey.patch_all()?
nz_21

gevent uyumluluğu için standart kitaplığı yamalar - gevent.org/api/gevent.monkey.html
38'de duyurulur
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.