运行时错误:在应用程序上下文之外工作.app.app_context()未解决问题



我正试图通过让一个进程池使用pool.map来运行一个耗时的循环。这个循环是视图函数的一部分,我把它放在一个新函数中,这样我就可以把它传递给pool.map

RuntimeError:在应用程序上下文之外工作。

这通常意味着您尝试使用所需的功能以某种方式与当前应用程序对象接口。解决使用app.app_context()设置应用程序上下文。请参阅有关详细信息,请参阅文档。

我确实将方法调用放在了with app.app_context()中(如上所述)。但这个错误并没有消失。请告诉我如何解决这个问题。

@app.route('/some_url', methods= ['POST'])
def view_function ():
start_time = time.time()
data = request.get_json()
a = round(data.get('a', '') * data.get('a', ''))
b = round(data.get('b', '') * data.get('b', ''))
c = round(data.get('c', '') * data.get('c', ''))
d = round(data.get('d', '') * data.get('d', ''))
a_id = select.get_id(data.get('property', ''), session['somedata'][1])
some_list, a_ids, loc = AnotherClassInDifferentDir.get_list(a_id, session['somedata'][1])
value = select.get_value(//some arguments)

这是我使用多处理的地方,也是我使用with app.app_context():(这是同一函数view_function的一部分)-的地方

with app.app_context():
e = data.get('e', '')
stuff = session['somedata'][1]
pool = Pool(processes = 2)
func = partial(loopTask,e, a_id, a_ids, a, b, c, d, loc, stuff)
stuff_array = [(index, item) for index, item in enumerate(some_list)]
print("stuff_array =", stuff_array)
pool.map(func, stuff_array)
pool.close()
pool.join()
print("--- %s seconds ---" % (time.time() - start_time))
return ''
def loopTask(e, a_ids, a, b, c, d, loc, stuff, stuff_item):
index, s = stuff_item
c_id = document_ids[index]
done = AnotherClassInDifferentDir.work(s)
f = AnotherClassInDifferentDir.more_work(done, a, b, c, d, loc)
if f != '':
update.update_work(//some arguments)
g.cnxn.commit()
if (moreDB.check(//some arguments) ==0):
update.work(//some arguments)
g.cnxn.commit()
else:
pass

我认为g.cnxn.commit()导致了这个问题,因为它是由应用程序上下文公开的,但我不确定。请帮忙!

编辑

g.cnxn使用装饰器@app.before_request以不同的方法设置

@app.before_request
def connect_to_database():
if request.endpoint != 'static':
if not hasattr(g,'cnxn'):
g.cnxn = pyodbc.connect('DRIVER={{Some Driver}};config1={};config2={};Trusted_connection=yes'.format(app.config['config1'],app.config['config2']))  

正如Flask文档中所指出的,应用程序上下文在请求之外不可用,当loopTask在不同的进程中运行时就会发生这种情况。考虑将您的应用程序实例传递给loopTask函数,并将其下使用with块中g命名空间对象的代码部分包装起来。不需要view_function中的with块,因为在请求过程中已经存在应用程序上下文。

编辑:因为我们在每个请求之前都要设置一个数据库连接,所以我们使用test_request_context。你可以在这里阅读更多关于它的信息。它是用于测试的,但出于我们的目的,它将允许我们在派生过程中建立数据库连接。

def loopTask(e, a_ids, a, b, c, d, loc, stuff, stuff_item, app):  # added app parameter 
index, s = stuff_item
c_id = document_ids[index]
with app.test_request_context('/some_url'):
app.preprocess_request()  # triggers 'connect_to_database'
done = AnotherClassInDifferentDir.work(s)
f = AnotherClassInDifferentDir.more_work(done, a, b, c, d, loc)
if f != '':
update.update_work(//some arguments)
g.cnxn.commit()
if (moreDB.check(//some arguments) ==0):
update.work(//some arguments)
g.cnxn.commit()
else:
pass

这意味着with块变为:

e = data.get('e', '')
stuff = session['somedata'][1]
pool = Pool(processes = 2)
func = partial(loopTask,e, a_id, a_ids, a, b, c, d, loc, stuff, stuff_item)
stuff_array = [(index, item) for index, item in enumerate(some_list)]
print("stuff_array =", stuff_array)
pool.map(func, (stuff_array, app))  # passing the `app` Flask instance here
pool.close()
pool.join()

这应该可以做到,但理想情况下,我们应该在loopTask中重用的函数中设置数据库连接。这样,我们就不需要test_request_context,而是使用app_context

最新更新