在Python Tornado Web Server中使用协同程序

时间:2018-03-13 12:49:30

标签: json python-2.7 websocket webserver tornado

我正在使用Python 2x开发一个用于Web浏览器游戏的自动汽车实现。我使用Tornado Web Server在localhost上运行游戏,我在名为“FrameHandler”的函数中使用JSON数据格式发布和接收游戏数据,并且我还确定了“to_dict_faster()”函数中汽车的行为。

在这里,我的问题是我可以在协同程序的帮助下将数据写入文本文件,该文件文件在特定时间间隔内保存在speed_data变量中。但是,我无法在这个特定的时间间隔内转储JSON数据,因为“FrameHandler”的作用类似于True,它总是请求转储数据。我想要做的是将所需的行为发送为在特定时间间隔内写入文本文件而不更改流帧处理程序,因为它会影响游戏的FPS。

我想知道我怎么能这样做很长一段时间任何帮助都会很棒:

@gen.coroutine
def sampler():
io_loop = tornado.ioloop.IOLoop.current()
start = time.time()
while True:
      with open("Sampled_Speed.txt", "a") as text_file:
          text_file.write("%d,%.2f\n" % (speed_data, ((time.time() - start))))
    yield gen.Task(io_loop.add_timeout, io_loop.time() + period)

class MainHandler(tornado.web.RequestHandler):
def get(self):
     self.redirect("/static/v2.curves.html")

class FrameHandler(tornado.web.RequestHandler):

    def post(self):
        global speed_data
        data = json.loads(self.get_arguments("telemetry")[0])
        ar = np.fromstring(base64.decodestring(self.request.body), dtype=np.uint8)
        image = ar.reshape(hp.INPUT_SIZE, hp.INPUT_SIZE, hp.NUM_CHANNELS)
        left, right, faster, slower = data["action"]
        terminal, action, all_data, was_start = (
            data["terminal"],
            Action(left=left, right=right, faster=faster, slower=slower),
            data["all_data"],
            data["was_start"]
        )

        for i in range(len(all_data)):
            data_dict=all_data[i]
            speed_data = data_dict[u'speed']
            position_data=data_dict[u'position']

        result_action = agent.steps(image, 0.1, terminal, was_start, action, all_data)

        if speed_data < 4000:
            self.write(json.dumps(result_action.to_dict_faster()))
        else:
            self.write(json.dumps(result_action.to_dict_constant()))

def make_app():
return tornado.web.Application([
    (r"/", MainHandler),
    (r"/frame", FrameHandler),
    (r"/static/(.*)", tornado.web.StaticFileHandler, {"path": static_path})
], debug=True)

if __name__ == "__main__":
app = make_app()
if "SERVER_PORT" in os.environ:
    port = int(os.environ["SERVER_PORT"])
else:
    port = 8880
print "LISTENING ON PORT: %d" % port
app.listen(port)
tornado.ioloop.IOLoop.current().run_sync(sampler)
tornado.ioloop.IOLoop.current().start()

1 个答案:

答案 0 :(得分:0)

您可以将文件写入另一个线程(例如使用tornado的run_on_executor),因此python解释器会在写入时自动从Sampler切换到主线程FrameHandler。但是你必须使用线程安全的speed_data变量,我以stdlib Queue.Queue为例:

class Handler(tornado.web.RequestHandler):
    @gen.coroutine
    def get(self):
        global speed_data
        speed_data.put("REALLY BIG TEST DATA\n")
        self.finish("OK")


class Sampler():
    executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)

    def __init__(self, queue):
        self._q = queue

    @run_on_executor
    def write_sample(self):
        with open("foobar.txt", "w") as f:
            while True:
                data = self._q.get()
                f.write(data)


if __name__ == '__main__':
    application = Application(
        [("/status", Handler)]
    )

    server = HTTPServer(application)
    server.listen(8888)

    speed_data = Queue.Queue()
    smp = Sampler(speed_data)
    IOLoop.current().add_callback(smp.write_sample)
    IOLoop.current().start()