【问题标题】:Python Twisted asynchronous scheduling without blockingPython Twisted 无阻塞异步调度
【发布时间】:2017-08-12 00:10:40
【问题描述】:

对不起标题,但不知道如何用一句话来描述我想要做的事情。基本上,我拥有的每个对象都足够快,不会在一次创建 1 个时阻塞,但如果我有十几个或数百个,那么它会阻塞主循环。我正在尝试找到一种方法来减少加载对象时发生的口吃量。本质上,我必须渲染每一帧的应用程序,如果超过一帧,应用程序就会开始出现抖动。

主要问题是当我创建对象时,他们必须从 json 文件中查找数据并导入。现在每个 json 文件本身都非常快(0.006 秒),比一帧的 1/60 快。但是,当计数器开始变为 x*0.006 时,就会出现问题。

有趣的是,如果我使用 deferToThread 之类的东西,它仍然会阻塞主循环。这是我想要做的。我希望这些对象立即可用,因为立即完成它们非常重要。然而,实际的 json 加载并不那么重要,我希望它以某种方式安排它,以便其他人开始“填写”,可以这么说,因为它们变得可用。它们的可用顺序也是不必要的。

from twisted.internet import reactor, defer
from profilehooks import profile
import json

objects = []

def print_test(text):
    print text

class JsonObject(object):
    def __init__(self, i):
        self.i = i
        self.json_data = None
        self.load() # <load data slowly somehow?>
        # Threads not working either?
        #d = threads.deferToThread(self.load)
        #d.addCallback(self.set_json_data)

    def load(self):
        with open("{0}.json".format(str(self.i).zfill(3))) as f:
            self.json_data = json.load(f)
        #return self.json_data


    def set_json_data(self, data):
        print "GOT DATA", self.i

def load_objects():
    for i in xrange(300):
        objects.append(JsonObject(i))

    print "LOADED ALL OBJECTS"

reactor.callLater(0, load_objects)
reactor.callLater(0.5, print_test, "test for blocking")
reactor.run()

【问题讨论】:

  • 试过 reactor.callLater(0.1, self.load())?
  • 也试过了,结果一样。
  • 对不起,现在来得太晚了,我现在想不出任何有用的东西......我通常把一些我不想干扰主程序的东西放到子进程中。你考虑过吗?

标签: python json multithreading asynchronous twisted


【解决方案1】:

基本上for i in xrange(300) 阻塞了你的主反应堆。这是一种简单的方法,可以在您的 load_objects 函数中稍作休息,并将控制权返回给反应器/事件循环,以便完成其他任务。

@defer.inlineCallbacks
def load_objects():
    for i in xrange(300):
        objects.append(JsonObject(i))

        if i % 100 == 0:
            yield    # take a break and let reactor do other tasks

        print("LOADED ALL OBJECTS")

还有cooperate 函数可以做类似的事情,但我一直觉得inlineCallbacks 更直观。

【讨论】:

  • 对不起,我不清楚,是的,我意识到我提供的示例会因为对象的数量而阻塞。它阻止它是因为 self.load() 对象在初始化时执行。如果我删除 self.load 它会立即加载。我想要做的是加载所有 JsonObject (因为它们本身很快就没有 init 上的加载功能),但是有它,所以每个人都安排了对 self.load 的调用,可以说是“展开”这样它不会阻塞。
  • 这就是这个答案的作用。这也是合作()会做的事情。与合作()的区别(这使它更好)是它基于时间的工作块而不是硬编码一些数字(可能太多 - 让你口吃 - 或太少 - 使过程花费更长的时间。
  • 另外,如果你使用得当, deferToThread 应该可以正常工作。您没有发布任何使用 deferToThread 的代码,因此很难说您可能做错了什么。
  • 这只会将其展开如果我将在 xrange 中调用它们,或者如果创建技术用作迭代器,则不会。忽略那个。我什至有 xrange 的唯一原因是为了展示它如何阻止的最小示例。我正在寻找的是,即使我创建了 300 个对象,无论如何,无论以何种方式,它都不会阻塞。非阻塞必须来自对象本身,而不是对象被创建的方式。我的示例确实有一个延迟线程示例(已注释掉),它也不起作用。
  • 如果我记得正确打开文件是一项同步任务,Python 或其他语言对此无能为力。这与操作系统如何在低级别处理文件有关。除此之外,如何每帧打开 300 多个 JSON 文件?此外,如果您每次打开这么多文件,最好设计某种缓存机制,因为正如您所注意到的,一次打开大量文件效率非常低。您还可以通过 C 模块或 python-cjson 之类的包来加速 JSON 加载,尽管它不会真正影响整个应用程序的速度
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-17
  • 1970-01-01
  • 1970-01-01
  • 2018-04-06
相关资源
最近更新 更多