【问题标题】:Converting Bottle FORMSDICT to a Python dictionary (in a thread safe way)将 Bottle FORMSDICT 转换为 Python 字典(以线程安全的方式)
【发布时间】:2015-01-08 00:48:31
【问题描述】:

我刚刚完成了 [bottle tutorial[1] 并找到了以下有用的表格(我希望我的格式正确),其中可以访问哪些类型的请求属性

Attribute           GET Form fields     POST Form fields    File Uploads
BaseRequest.query   yes                 no                  no
BaseRequest.forms   no                  yes                 no
BaseRequest.files   no                  no                  yes
BaseRequest.params  yes                 yes                 no
BaseRequest.GET     yes                 no                  no
BaseRequest.POST    no                  yes                 yes

我当然想自己尝试一下,但是因为 Bottle 数据结构是特殊的线程安全版本,并且我想使用 json 以合理的格式打印它,所以我编写了以下(工作)测试程序

from bottle import run, route, request, response, template, Bottle
import uuid
import json
import os

ondersoek = Bottle()

@ondersoek.get('/x')
@ondersoek.post('/x')
def show_everything():
   PythonDict={}
   PythonDict['forms']={}
   for item in request.forms:
      PythonDict['forms'][item]=request.forms.get(item)

   PythonDict['query']={}
   for item in request.forms:
      PythonDict['query'][item]=request.query.get(item)

   #The below does not work - multipart/form-data doesn't serialize in json
   #PythonDict['files']={}
   #for item in request.files:
      #PythonDict['files'][item]=request.files.get(item)

   PythonDict['GET']={}
   for item in request.GET:
      PythonDict['GET'][item]=request.GET.get(item)

   PythonDict['POST']={}
   for item in request.POST:
      PythonDict['POST'][item]=request.POST.get(item)

   PythonDict['params']={}
   for item in request.params:
      PythonDict['params'][item]=request.params.get(item)

   return json.dumps(PythonDict, indent=3)+"\n"

ondersoek.run(host='localhost', port=8080, reloader=True)

这行得通,我明白了:

tahaan@Komputer:~/Projects$ curl -G -d dd=dddd http://localhost:8080/x?q=qqq
{
   "files": {}, 
   "GET": {
      "q": "qqq", 
      "dd": "dddd"
   }, 
   "forms": {}, 
   "params": {
      "q": "qqq", 
      "dd": "dddd"
   }, 
   "query": {}, 
   "POST": {}
}

tahaan@Komputer:~/Projects$ curl -X POST -d dd=dddd http://localhost:8080/x?q=qqq
{
   "files": {}, 
   "GET": {
      "q": "qqq"
   }, 
   "forms": {
      "dd": "dddd"
   }, 
   "params": {
      "q": "qqq", 
      "dd": "dddd"
   }, 
   "query": {
      "dd": null
   }, 
   "POST": {
      "dd": "dddd"
   }
}

我很确定这不是线程安全的,因为我一次将数据从 Bottle 数据结构复制到 Python 本机数据结构中。现在我仍在使用默认的非线程服务器,但出于性能原因,我希望在将来的某个时候使用像 CherryPy 这样的线程服务器。因此,问题是如何将数据从 Bottle 或任何其他类似的线程安全字典中获取到可以转换为 JSON(轻松)的东西? Bottle 是否会在某处公开 FormsDict-To-Json 函数?

【问题讨论】:

  • 虽然我不特别了解Bottle,但您的问题有点令人困惑。你说Bottle 数据结构线程安全的,因此你认为使用访问它们不是是线程安全的乙>?我认为线程安全意味着访问是线程安全的。
  • 我确信还有其他有趣和/或更好的方法可以实现与您的代码相同的目标,但如果一切都为您工作......也许它不是“好得令人难以置信”?
  • 我应该澄清我的问题,尽管我确实说过我是在问“供将来参考”。是的,它正在工作,我今天没有线程问题。但是明天我可能不会在 CherryPy 后面使用 Bottle。而Non-thread-safe部分是通过Bottle外部的bottle数据类型的迭代,慢慢地将数据从一个线程安全的结构复制到一个非线程安全的结构中。
  • 你觉得哪一部分不是线程安全的?抄出还是抄入?
  • 好的,那么恕我直言,您对大多数编程语言中代码执行方式的基础知识存在误解。教程可能会有所帮助。我没有对此的快速链接,但this section of the Python Language Reference 中涵盖了一些相同的概念

标签: python json dictionary bottle


【解决方案1】:

您的代码线程安全的。也就是说,如果你在多线程服务器中运行它,它会工作得很好。

这是因为多线程服务器仍然只为每个线程分配一个请求。您没有全局数据;代码中的所有数据都包含在单个请求中,这意味着它在单个线程中。

例如,Request object 的 Bottle 文档说(强调我的):

一个线程本地子类 BaseRequest 为每个线程具有一组不同的属性。那里 通常只是这个类的一个全局实例(请求)。如果 在请求/响应周期内访问,此实例始终引用 到当前请求(即使在多线程服务器上)

换句话说,每次您在代码中访问request 时,Bottle 都会做一些“魔术”来为您提供一个线程本地的 Request 对象。这个对象不是全局的;它不同于可能同时存在的所有其他请求对象,例如在其他线程中。因此,它是线程安全的。


编辑特别回答您关于 PythonDict 的问题:此行使您的代码线程安全:

PythonDict={}

这是安全的,因为每次线程遇到该行代码时,您都会创建一个 new dict;并且您创建的每个 dict 对于创建它的线程都是本地的。 (用更专业的术语来说:它在堆栈上。)

这与您的线程共享 global dict 的情况相反;在这种情况下,您的怀疑是正确的:它不是线程安全的。但在您的代码中,dict 是本地的,因此不存在线程安全问题。

希望有帮助!

【讨论】:

  • 我担心另一个线程可能会踩到PythonDict - 换句话说,两个线程从请求对象的两个安全、不同的“实例”复制,将数据添加到单个 Python 字典变量中。
  • 但是问题中没有共享的 PythonDict。每次调用 show_everything 时,都会创建新的(本地)PythonDicts。你同意吗?
  • 好的,我现在看到了区别。我怎样才能故意创建一个跨线程共享对象,例如用作数据库连接池?
  • 酷。这是一个新问题——但简而言之:创建一个 global 对象。
  • 如果您发现此答案有帮助,请不要忘记接受或投票。谢谢!
【解决方案2】:

据我所知,没有理由相信线程存在问题,因为您的请求是由 Bottle 在单个线程中处理的。此外,您自己的代码中没有异步调用可以产生访问共享变量的新线程。

【讨论】:

  • 当使用带有 CherryPy 的 Bottle 时,证明多个实例可以同时运行是微不足道的。但是,我在测试中未能产生实例覆盖彼此变量的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-30
  • 1970-01-01
相关资源
最近更新 更多