为什么子线程无法访问flask_login中的current_user变量? [英] Why child threads cannot access the current_user variable in flask_login?

查看:77
本文介绍了为什么子线程无法访问flask_login中的current_user变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写 Flask应用程序,并尝试为某些与服务器相关的功能插入多线程实现.我注意到了这种奇怪的行为,所以我想了解为什么会发生这种情况以及如何解决它.我有以下代码:

I am writing a Flask application and I am trying to insert a multi-threaded implementation for certain server related features. I noticed this weird behavior so I wanted to understand why is it happening and how to solve it. I have the following code:

from flask_login import current_user, login_required
import threading

posts = Blueprint('posts', __name__)

@posts.route("/foo")
@login_required
def foo():
    print(current_user)
    thread = threading.Thread(target=goo)
    thread.start()
    thread.join()
    return


def goo():
    print(current_user)
    # ...

主进程正确打印 current_user ,而子线程打印 None .

The main process correctly prints the current_user, while the child thread prints None.

User('Username1', 'email1@email.com', 'Username1-ProfilePic.jpg')
None

为什么会这样?如何在子进程中也设法获取 current_user ?我尝试将其作为 goo 的参数传递,但是我仍然得到相同的行为.

Why is it happening? How can I manage to obtain the current_user also in the child process? I tried passing it as argument of goo but I still get the same behavior.

我发现了这篇文章,但我不明白如何确保上下文不存在在这种情况下发生了变化,因此我尝试提供一个更简单的示例.

I found this post but I can't understand how to ensure the context is not changing in this situation, so I tried providing a simpler example.

我尝试将新创建的对象 User 作为参数传递,该对象中填充了 current_user

I tried passing as parameter also a newly created object User populated with the data from current_user

def foo():
    # ...
    user = User.query.filter_by(username=current_user.username).first_or_404()
    thread = threading.Thread(target=goo, args=[user])
    # ...

def goo(user):
    print(user)
    # ...

它可以正确打印当前用户的信息.但是由于在 goo 内部,我也在执行数据库操作,因此出现以下错误:

And it correctly prints the information of the current user. But since inside goo I am also performing database operations I get the following error:

RuntimeError:未找到应用程序.在视图函数中进行任何工作或推送应用程序上下文.看 http://flask-sqlalchemy.pocoo.org/contexts/.

所以我怀疑我认为这是上下文问题.

So as I suspected I assume it's a problem of context.

我也尝试按照错误提示将其插入 goo 内:

I tried also inserting this inside goo as suggested by the error:

def goo():
    from myapp import create_app
    app = create_app()
    app.app_context().push()
    # ... database access

但是我仍然遇到相同的错误,如果尝试打印 current_user ,我会得到 None .

But I still get the same errors and if I try to print current_user I get None.

如何将旧上下文传递给新线程?还是我应该创建一个新的?

How can I pass the old context to the new thread? Or should I create a new one?

推荐答案

这是因为Flask使用线程局部变量为每个请求的线程存储此变量.在许多情况下,这简化了操作,但是却很难使用多个线程.请参见 https://flask.palletsprojects.com/en/1.1.x/design/#thread-local .

This is because Flask uses thread local variables to store this for each request's thread. That simplifies in many cases, but makes it hard to use multiple threads. See https://flask.palletsprojects.com/en/1.1.x/design/#thread-local.

如果要使用多个线程来处理单个请求,则Flask可能不是最佳选择.如果需要,您总是可以只在初始线程上与Flask进行交互,然后通过某种共享对象在其他线程上来回转发自己需要的任何东西.对于辅助线程上的数据库访问,只要不使用Flask,就可以将线程安全的数据库库与多个线程一起使用.

If you want to use multiple threads to handle a single request, Flask might not be the best choice. You can always interact with Flask exclusively on the initial thread if you want and then forward anything you need on other threads back and forth yourself through a shared object of some kind. For database access on secondary threads, you can use a thread-safe database library with multiple threads as long as Flask isn't involved in its usage.

总而言之,将Flask视为单线程.任何额外的线程都不应直接与Flask交互,以免出现问题.您也可以考虑根本不使用线程并按顺序运行所有内容,或者尝试例如龙卷风和asyncio可以根据需要轻松实现与协程的并发.

In summary, treat Flask as single threaded. Any extra threads shouldn't interact directly with Flask to avoid problems. You can also consider either not using threads at all and run everything sequentially or trying e.g. Tornado and asyncio for easier concurrency with coroutines depending on the needs.

这篇关于为什么子线程无法访问flask_login中的current_user变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆