Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 应用程序引擎上的后台任务_Python_Google App Engine_Cron - Fatal编程技术网

Python 应用程序引擎上的后台任务

Python 应用程序引擎上的后台任务,python,google-app-engine,cron,Python,Google App Engine,Cron,如何在App Engine上运行后台任务?GAE是构建可伸缩web应用程序的非常有用的工具。许多人指出的一些限制包括不支持后台任务、缺少定期任务以及严格限制每个HTTP请求所需的时间,如果请求超过该时间限制,操作将终止,这使得运行耗时的任务变得不可能 如何运行后台任务? 在GAE中,代码仅在有HTTP请求时执行。代码所需时间有严格的时间限制(我想是10秒)。所以,若并没有请求,那个么代码就不会执行。建议的解决方法之一是使用外部框连续发送请求,这样可以创建一个后台任务。但为此,我们需要一个外部框,

如何在App Engine上运行后台任务?

GAE是构建可伸缩web应用程序的非常有用的工具。许多人指出的一些限制包括不支持后台任务、缺少定期任务以及严格限制每个HTTP请求所需的时间,如果请求超过该时间限制,操作将终止,这使得运行耗时的任务变得不可能

如何运行后台任务?
在GAE中,代码仅在有HTTP请求时执行。代码所需时间有严格的时间限制(我想是10秒)。所以,若并没有请求,那个么代码就不会执行。建议的解决方法之一是使用外部框连续发送请求,这样可以创建一个后台任务。但为此,我们需要一个外部框,现在我们依赖于一个以上的元素。另一种选择是发送302重定向响应,以便客户端重新发送请求,这也使我们依赖于外部元素,即客户端。如果那个外部盒子是GAE本身呢?所有使用过函数式语言但不支持循环构造的人都知道,ie递归是循环的替代品。那么,如果我们完成了部分计算,并在很短的时间内(比如说1秒)在同一个url上进行HTTP访问,会怎么样呢?这将在apache上运行的php代码上创建一个循环(递归)

<?php $i = 0; if(isset($_REQUEST["i"])){ $i= $_REQUEST["i"]; sleep(1); } $ch = curl_init("http://localhost".$_SERVER["PHP_SELF"]."?i=".($i+1)); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_TIMEOUT, 1); curl_exec($ch); print "hello world\n"; ?> 有些人认为这在GAE上不起作用。那么,如果我们在其他url上使用HTTP,比如说url2,HTTP在第一个url上使用哪一个呢?这似乎在GAE中起作用。代码如下所示

class FirstUrl(webapp.RequestHandler): def get(self): self.response.out.write("ok") time.sleep(2) urlfetch.fetch("http://"+self.request.headers["HOST"]+'/url2') class SecondUrl(webapp.RequestHandler): def get(self): self.response.out.write("ok") time.sleep(2) urlfetch.fetch("http://"+self.request.headers["HOST"]+'/url1') application = webapp.WSGIApplication([('/url1', FirstUrl), ('/url2', SecondUrl)]) def main(): run_wsgi_app(application) if __name__ == "__main__": main() 类FirstUrl(webapp.RequestHandler): def get(自我): self.response.out.write(“ok”) 时间。睡眠(2) urlfetch.fetch(“http://”+self.request.headers[“主机”]+'/url2') 类SecondUrl(webapp.RequestHandler): def get(自我): self.response.out.write(“ok”) 时间。睡眠(2) urlfetch.fetch(“http://”+self.request.headers[“主机”]+'/url1') application=webapp.WSGIApplication([('/url1',FirstUrl),('/url2',SecondUrl)]) def main(): 运行应用程序(应用程序) 如果名称=“\uuuuu main\uuuuuuuu”: main() 因为我们找到了一种运行后台任务的方法,所以让我们为周期性任务(计时器)和跨多个HTTP请求(foreach)的循环构造构建抽象

定时器
现在,构建计时器是直接向前的。基本思想是要有一个计时器列表以及调用每个计时器的时间间隔。一旦我们到达这个时间间隔,调用回调函数。我们将使用memcache来维护计时器列表。为了确定何时调用回调,我们将在memcache中存储一个密钥,并以interval作为过期时间。我们定期(比如5秒)检查该键是否存在,如果不存在,则调用回调并再次设置该键的间隔

def timer(func, interval): timerlist = memcache.get('timer') if(None == timerlist): timerlist = [] timerlist.append({'func':func, 'interval':interval}) memcache.set('timer-'+func, '1', interval) memcache.set('timer', timerlist) def checktimers(): timerlist = memcache.get('timer') if(None == timerlist): return False for current in timerlist: if(None == memcache.get('timer-'+current['func'])): #reset interval memcache.set('timer-'+current['func'], '1', current['interval']) #invoke callback function try: eval(current['func']+'()') except: pass return True return False def定时器(函数,间隔): timerlist=memcache.get('timer') 如果(无==时间列表): timerlist=[] 追加({'func':func,'interval':interval}) memcache.set('timer-'+func,'1',interval) memcache.set('timer',timerlist) def checktimers(): timerlist=memcache.get('timer') 如果(无==时间列表): 返回错误 对于时间列表中的电流: 如果(None==memcache.get('timer-'+current['func']): #重置间隔 memcache.set('timer-'+当前['func'],'1',当前['interval']) #调用回调函数 尝试: 评估(当前['func']+'()') 除: 通过 返回真值 返回错误 Foreach
当我们想进行长时间的计算时,比如说对1000个数据库行执行一些操作或获取1000个URL等,这是必需的。基本思想是在memcache中维护回调和参数列表,每次使用参数调用回调

def foreach(func, args): looplist = memcache.get('foreach') if(None == looplist): looplist = [] looplist.append({'func':func, 'args':args}) memcache.set('foreach', looplist) def checkloops(): looplist = memcache.get('foreach') if(None == looplist): return False if((len(looplist) > 0) and (len(looplist[0]['args']) > 0)): arg = looplist[0]['args'].pop(0) func = looplist[0]['func'] if(len(looplist[0]['args']) == 0): looplist.pop(0) if((len(looplist) > 0) and (len(looplist[0]['args']) > 0)): memcache.set('foreach', looplist) else: memcache.delete('foreach') try: eval(func+'('+repr(arg)+')') except: pass return True else: return False # instead of # foreach index in range(0, 1000): # someoperaton(index) # we will say # foreach('someoperaton', range(0, 1000)) def foreach(函数,参数): looplist=memcache.get('foreach') 如果(无==循环列表): looplist=[] looplist.append({'func':func,'args':args}) memcache.set('foreach',looplist) def checkloops(): looplist=memcache.get('foreach') 如果(无==循环列表): 返回错误 如果((len(looplist)>0)和(len(looplist[0]['args'])>0)): arg=looplist[0]['args'].pop(0) func=looplist[0]['func'] 如果(len(looplist[0]['args'])==0): looplist.pop(0) 如果((len(looplist)>0)和(len(looplist[0]['args'])>0)): memcache.set('foreach',looplist) 其他: memcache.delete('foreach') 尝试: eval(func+'('+repr(arg)+')) 除: 通过 返回真值 其他: 返回错误 #而不是 #范围(0,1000)内的foreach索引: #某些操作(索引) #我们会说 #foreach('someoperation',范围(0,1000)) 现在构建一个每一小时获取URL列表的程序是很简单的。这是代码

def getone(url): try: result = urlfetch.fetch(url) if(result.status_code == 200): memcache.set(url, '1', 60*60) #process result.content except : pass def getallurl(): #list of urls to be fetched urllist = ['http://www.google.com/', 'http://www.cnn.com/', 'http://www.yahoo.com', 'http://news.google.com'] fetchlist = [] for url in urllist: if (memcache.get(url) is None): fetchlist.append(url) #this is equivalent to #for url in fetchlist: getone(url) if(len(fetchlist) > 0): foreach('getone', fetchlist) #register the timer callback timer('getallurl', 3*60) def getone(url): 尝试: 结果=urlfetch.fetch(url) 如果(result.status_code==200): memcache.set(url'1',60*60) #处理结果.内容 除: 通过 def getallurl(): #要获取的URL列表 urllist=['http://www.google.com/', 'http://www.cnn.com/', 'http://www.yahoo.com', 'http://news.google.com'] fetchlist=[] 对于url列表中的url: 如果(memcache.get(url)为无): fetchlist.append(url) #这相当于 #对于fetchlist中的url:getone(url) 如果(len(fetchlist)>0): foreach('getone',fetchlist) #注册计时器回调 计时器('getallurl',3*60) 完整的代码在这里 我已经在appengine上运行这段代码好几天了,没有什么问题


警告:我们大量使用urlfetch。每天的urlfetch数量限制为160000。所以要小心不要达到那个极限。

新的运行时版本将有某种定期执行引擎a'la cron。请参见关于AppEngine组的内容

因此,所有SDK片段都出现了
from google.appengine.ext import deferred

def do_something_expensive(a, b, c=None):
    logging.info("Doing something expensive!")
    # Do your work here

# Somewhere else
deferred.defer(do_something_expensive, "Hello, world!", 42, c=True)