【问题标题】:Does django + mod_wsgi require threaded programming discipline?django + mod_wsgi 是否需要线程编程规则?
【发布时间】:2012-10-25 19:21:02
【问题描述】:

我们正在 mod_wsgi 下推出我们的第一个 django 应用程序

`WSGIDaemonProcess our-appname processes=6 threads=15'`

我们正在讨论我们的 Python 代码以及它使用的 Redis 和 Postgres 库是否需要是线程安全的。

从阅读 mod_wsgi 文档中我可以看出,即使 apache worker 正在使用多个 apache 线程处理请求,我们的 python 代码也适用于所有意图和目的单线程。我在 mod_wsgi 文档上没有看到任何警告说“当心!您现在必须担心全局数据和线程安全!”但也没有明确的“不要担心没有线程”。

我们没有在 Python 代码中明确地对线程做任何事情,在我们编写的任何内容中都没有提及它们。

但这里的一些人认为,由于我们使用threads=15 运行,因此我们现在处于多线程世界中。

谁能澄清这里实际发生了什么?我们的 Python 代码现在是否可以通过以前没有的相同数据执行多个线程?

【问题讨论】:

    标签: python django thread-safety mod-wsgi


    【解决方案1】:

    是的,显然您正在运行多线程应用程序,如果您不注意全局变量、类属性等,就会产生问题

    如果您需要全局保存某些内容,请将其保存在线程本地存储中。

    这是modwsgi doc, Building_A_Portable_Application的引述

    3 .应用程序必须是可重入的,或者简单地说,能够被多个线程同时调用。数据 需要在请求的生命周期内存在,需要存储为 基于堆栈的数据、线程本地数据或缓存在 WSGI 应用程序中 环境。实际应用模块中的全局变量 不能用于此目的。

    所以我认为你已经得到了足够的警告。

    【讨论】:

      【解决方案2】:

      python 解释器不是线程安全的,特别是因为引用计数,所以线程不能同时访问同一进程空间中的 python 对象。您无法无意或有意地配置 mod_wsgi 来解决此问题,因为解释器受 GIL(全局解释器锁)保护。因此,您不必担心并发线程访问相同内存对象(内存锁定等)的风险带来的特别棘手的线程安全问题。

      一些网络服务器(例如带有 gevent 支持者的 gunicorn)将同时在内存中拥有多个线程,因此无需在 I/O(数据库访问、网络访问等)上阻塞单个进程。 mod_wsgi 也可能是这种情况。但是,这是以这样一种方式实现的,您不需要在应用程序代码中担心它——如果您的应用程序在多处理中使用是安全的,那么在这种有限的非并发线程中使用它也应该是安全的型号。

      当然,您不能在应用程序运行时使用全局变量或动态编辑应用程序的某些部分,但是如果您在 Django 中执行类似的操作,那么在您不必担心线程之前就会遇到问题。 Django 和其他 Web 框架的设计使得数据作为请求传入并作为响应传出,而不必担心该模型中的线程/进程安全性。

      对于任何 Web 应用程序,您确实需要担心对数据存储(尤其是数据库条目)的并发访问。在数据库访问方面进行防御性代码。

      【讨论】:

      • 对不起,我发现你的词组开头很混乱。 Python 解释器本身是线程安全的,如果不是,它就会到处崩溃。正如您所说,Python 解释器的内部状态和引用计数的管理由 GIL 进行调解,并确保使用多线程的 Python 解释器是安全的。这么糟糕的解释方式。带有 gevent 的 gunicorn 也没有多个线程。当使用 gevent 时,它们在技术上是协程而不是线程,尽管它使它们看起来像线程。
      • 现在应用程序级代码是线程安全的问题是另一个问题,但不要将其与 Python 解释器是否是线程安全的混淆。
      • 首先,我想这是真的,尽管我不确定将 python 解释器描述为对 python 对象的内存操作不是线程安全的是否比它更准确解释它是线程安全的,因为 GIL 阻止线程执行上述操作。关于第二点,我同意; gevent 使用技术上不是线程的“绿色线程”——我应该解释一下。
      • 不幸的是,人们习惯于抓住诸如“python 解释器不是线程安全的”之类的短语,并且在不了解上下文的情况下将其拿走,仅此而已。我们不想让人们认为 Python 只不过是一门美妙的语言。所以只是认为值得澄清。
      • 我在协调该线程上的其他评论时遇到问题,该评论说:“应用程序必须可重入”与您说的评论:“Django 和其他 Web 框架的设计是为了数据作为请求传入并作为响应传出,而不必担心该模型中的线程/进程安全性。”这两种说法似乎相互矛盾。我是不是误会了什么?
      【解决方案3】:

      我认为 Andrew 的回答有点误导。 CPython(注意还有其他 Python 实现,例如 Jython 和 PyPy)具有 GIL 的事实并不意味着您不必担心您的代码是线程安全的!由于 GIL,一个进程中的两个线程不能同时处于活动状态。但是并行性是通过定期在线程之间切换来模拟的。在您的程序执行期间,这种上下文切换可能随时发生。例如,如果您有一个模块 foo 包含一个“全局”变量 x,那么以下方法可能会输出 2、3、4、... 中的任何内容,具体取决于执行相同方法的线程数:

      def bar():
          foo.x = 1
          # a context switch might happen here!
          foo.x = foo.x + 1
          # or here!
          print(foo.x)
      

      其实你可以配置mod_wsgi使用max。 1个线程。然后你不必担心线程安全。但是你的程序的正确性将取决于网络服务器的配置,这是一个非常不可取的情况。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-05-08
        • 1970-01-01
        • 2015-04-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多