2017-07-04 17 views
10

Bir Django uygulaması üzerinde çalışıyorum. İstenirse, birkaç kez tekrarlanması gereken bir işlev yürütmesi gereken bir API son noktaya sahibim (belirli bir koşul doğru olana kadar). Şu anda onunla uğraşıyorum nasıl -Django - her x saniyede bir işlev çalıştırın

def shut_down(request): 
    # Do some stuff 
    while True: 
    result = some_fn() 
    if result: 
     break 
    time.sleep(2) 

    return True 

Bu korkunç bir yaklaşım olduğunu biliyoruz iken ve ben 2 saniye engelleme gerektiğini, bunun etrafında nasıl çözemiyorum .
Bu, 4 saniye bekledikten sonra çalışır. Ancak, döngüyü arka planda çalıştıran bir şeyden hoşlanırım ve some_fn True değerini döndürdüğünde durur.
Okuma Oz123 cevabı bana iş gibi görünüyor bir fikir verdi -

DÜZENLEME (Ayrıca, doğru dönecektir some_fn kesindir). İşte ne yaptım -

def shut_down(params): 
    # Do some stuff 
    # Offload the blocking job to a new thread 

    t = threading.Thread(target=some_fn, args=(id,), kwargs={}) 
    t.setDaemon(True) 
    t.start() 

    return True 

def some_fn(id): 
    while True: 
     # Do the job, get result in res 
     # If the job is done, return. Or sleep the thread for 2 seconds before trying again. 

     if res: 
      return 
     else: 
      time.sleep(2) 

Bu benim için işi yapar. Bu basit ama çok iş parçacığının Django ile ne kadar verimli olduğunu bilmiyorum.
Eğer herhangi bir kişi bunun tuzaklarına işaret edebilirse, eleştiri takdir edilir.

+1

Bunun için kereviz kullanabilirsiniz. El kitabını burada bulabilirsiniz: https://realpython.com/blog/python/asynchronous-tasks-with-django-and-celery/#periodic-tasks – neverwalkaloner

+0

@neverwalkaloner tam olarak neye ihtiyacım var gibi geliyor. Kullanmayı deneyeceğim, teşekkürler. :) – Zeokav

+1

@neverwalkaloner tarafından bahsettiğiniz gibi kereviz kullanabilirsiniz, programlı periyodik görevi ayarlayabilir, dokümanın çok esnek olduğunu kontrol edebilirsiniz http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html crontab modülüne bir göz atın. –

cevap

5

:

sette sonra, kodu değiştirebilir. schedule'u kullanabileceğiniz bu projeler için kullanımı çok kolaydır. Eğer herhangi bir fonksiyon periyodik bir görevi yürütmek yapabilirsiniz Bu kütüphane ile

:

import schedule 
import time 

def job(): 
    print("I'm working...") 

schedule.every(10).minutes.do(job) 
schedule.every().hour.do(job) 
schedule.every().day.at("10:30").do(job) 
schedule.every().monday.do(job) 
schedule.every().wednesday.at("13:15").do(job) 

while True: 
    schedule.run_pending() 
    time.sleep(1) 

örnek bir engelleme şekilde çalışır, ancak FAQ bakarsanız, siz de görevleri çalıştırabilir olduğunu göreceksiniz paralel iplik, engelleme ve artık bir kez gerekli değildir görevi kaldırmak olmadığını böyle: zamanlama ithalat Zamanlayıcı Burada

def run_continuously(self, interval=1): 
    """Continuously run, while executing pending jobs at each elapsed 
    time interval. 
    @return cease_continuous_run: threading.Event which can be set to 
    cease continuous run. 
    Please note that it is *intended behavior that run_continuously() 
    does not run missed jobs*. For example, if you've registered a job 
    that should run every minute and you set a continuous run interval 
    of one hour then your job won't be run 60 times at each interval but 
    only once. 
    """ 

    cease_continuous_run = threading.Event() 

    class ScheduleThread(threading.Thread): 

     @classmethod 
     def run(cls): 
      while not cease_continuous_run.is_set(): 
       self.run_pending() 
       time.sleep(interval) 

    continuous_thread = ScheduleThread() 
    continuous_thread.setDaemon(True) 
    continuous_thread.start() 
    return cease_continuous_run 


Scheduler.run_continuously = run_continuously 

bir sınıf yöntemi kullanım için bir örnektir:

def foo(self): 
     ... 
     if some_condition(): 
      return schedule.CancelJob # a job can dequeue it 

    # can be put in __enter__ or __init__ 
    self._job_stop = self.scheduler.run_continuously() 

    logger.debug("doing foo"...) 
    self.foo() # call foo 
    self.scheduler.every(5).seconds.do(
     self.foo) # schedule foo for running every 5 seconds 

    ... 
    # later on foo is not needed any more: 
    self._job_stop.set() 

    ... 

    def __exit__(self, exec_type, exc_value, traceback): 
     # if the jobs are not stop, you can stop them 
     self._job_stop.set() 
+0

Aslında, Celery'den (şimdilik) kaçınmanın yollarını aradım çünkü projemde sadece bir veya iki yerde planlamaya ihtiyacım var. Bu haha ​​gibi bir şeye rastladım! Bunu uygulamaya çalışacağım ve herhangi bir sorum varsa geri döneceğim. Cevap için teşekkürler! :) – Zeokav

+0

Aşağıda bir cevap yayınladım. Bunun daha sonra sorunlara yol açıp açmayacağını söylerseniz çok memnun olurum. – Zeokav

+0

İlginç bir kural - 'run_continuously' yöntemini ekleyen 'Zamanlayıcı'dan miras kalan bir sınıf oluşturmamanın herhangi bir nedeni var mı? Hemen biraz daha açık olanı yapardı. – Tim

1

Celery'ın task yönetimini kullanmanızı öneririz. Bu uygulamayı kurmak için this numaralı telefona başvurabilirsiniz ( javaScript arka planındaysanız paketini). kereviz aşırı öldürmek olduğunu birçok küçük projeler için

@app.task 
def check_shut_down(): 
    if not some_fun(): 
     # add task that'll run again after 2 secs 
     check_shut_down.delay((), countdown=3) 
    else: 
     # task completed; do something to notify yourself 
     return True 
İlgili konular