非同期ヒット

画像 おそらく誰かがすでに推測したように、この記事では、ソケットと、ソケットを簡単に操作できるフレームワークについて説明します。 最近、私は新しいプロジェクト、オンラインゲームの仕事を始めました。 このようなプロジェクトの場合、もちろんこれがターンベースの戦略でない限り、サーバーからの応答時間は非常に重要です。 それでは、厳しいリソース制約でこれをどのように達成できますか?



主な質問は残っていますが、ユーザーがアクションを実行するとどうなりますか? 通常のAjaxリクエストは機能しません。その理由は明らかです。 したがって、ソケットが役立ちます。



先史時代


ゲームはフラッシュ上に構築されておらず、jsはソケットの操作方法を知らないため、この問題に対処するフラッシュ基板を使用できます。 ここでは、小さなjsocketライブラリが役立ちます。

サーバーについては、まず、Twistedに注意が向けられ、すでに何かを書き始めました。私は自分で、たくさんの興味深いツールを発見しました。 それらのそれぞれについての情報を検索した後、興味深い記事を見つけました。 ただし、必要なタスクとは若干異なるタスクが考慮されるため、テストを実施することにしました。



スクリプト


ツイストテスト用のシンプルなクライアントを作成しています。


from twisted.internet.protocol import ClientFactory from twisted.protocols.basic import LineReceiver from twisted.internet import epollreactor epollreactor.install() from twisted.internet import reactor import sys,time clients=30000 host='127.0.0.1' port=8001 file = open( 'log.dat', 'w') class glob(): connections=0 crefuse=0 clost=0 def enchant(self): self.connections+=1 def refuse(self): self.crefuse+=1 def lost(self): self.clost+=1 a=glob() class EchoClient(LineReceiver): measure=True def connectionMade(self): self.sendLine("Hello, world!") self.t1 = time.time() def lineReceived(self, line): if self.measure: self.t2 = time.time() - self.t1 file.write('%s %s %s %s %s\n' % (a.connections+1,self.t2,a.crefuse,a.clost,line)) self.measure=False if a.connections+1 < clients: a.enchant() reactor.connectTCP(host, port, EchoClientFactory()) else: self.transport.loseConnection() class EchoClientFactory(ClientFactory): protocol = EchoClient def clientConnectionFailed(self, connector, reason): a.refuse() def clientConnectionLost(self, connector, reason): a.lost() def main(): f = EchoClientFactory() reactor.connectTCP(host, port, f) reactor.run() file.close() if __name__ == '__main__': main()
      
      





そして、すべてのフレームワーク上のサーバー。


ゲベント


 clients=[] host='' port = 8001 def echo(socket, address): clients.append(socket) while True: line = socket.recv(1024) for client in clients: try: client.send(str(len(clients))+'\r\n') except: clients.remove(client) if __name__ == '__main__': from gevent.server import StreamServer StreamServer((host, port), echo).serve_forever()
      
      







竜巻


 import errno import functools import socket from tornado import ioloop, iostream host='' port = 8001 clients=[] class Connection(object): def __init__(self, connection): clients.append(self) self.stream = iostream.IOStream(connection) self.read() def read(self): self.stream.read_until('\r\n', self.eol_callback) def eol_callback(self, data): for c in clients: try: c.stream.write(str(len(clients))+'\r\n') except: clients.remove(c) self.read() def connection_ready(sock, fd, events): while True: try: connection, address = sock.accept() except socket.error, e: if e[0] not in (errno.EWOULDBLOCK, errno.EAGAIN): raise return connection.setblocking(0) Connection(connection) if __name__ == '__main__': sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setblocking(0) sock.bind((host, port)) sock.listen(30000) io_loop = ioloop.IOLoop.instance() callback = functools.partial(connection_ready, sock) io_loop.add_handler(sock.fileno(), callback, io_loop.READ) try: io_loop.start() except KeyboardInterrupt: io_loop.stop() print "exited cleanly"
      
      







ねじれた


 from twisted.protocols import basic class MyChat(basic.LineReceiver): def connectionMade(self): self.factory.clients.append(self) def connectionLost(self, reason): self.factory.clients.remove(self) def dataReceived(self, line): for c in self.factory.clients: c.message(str(len(factory.clients))+'\r\n') def message(self, message): self.transport.write(message) from twisted.internet import epollreactor epollreactor.install() from twisted.internet import reactor, protocol from twisted.application import service, internet factory = protocol.ServerFactory() factory.protocol = MyChat factory.clients = [] reactor.listenTCP(8001,factory) reactor.run()
      
      







少し説明


実際、チャットサーバーを作成し、サーバーがクライアントから行を受信するとすぐに、この行をすべての接続クライアントに送信します(より正確には、接続クライアントの数を送信します)。 したがって、負荷は算術的に増加します。 クライアントは、サーバーにメッセージを送信してから応答を受信するまでの経過時間を測定します。 現在のクライアントが最後に接続したので、すべてのクライアントはすでにこの時間までに応答を受け取ります。



測定中に、接続したユーザーの数に対する応答時間を取りました。 クライアントとサーバーはローカルホストで起動されました。 マシンはデスクトップとして使用されるため、結果はわずかに歪む可能性がありますが、本質は明らかです。 最大30,000接続までの依存関係を測定することを計画していましたが、残念ながら3つのフレームワークすべてでこれは長すぎることが判明しました。

画像

応答軸では、時間はもちろん秒単位です。

竜巻グラフには2本の線が表示されます。 これらは2つのテストではありませんが、1つだけ、この種類の結果です。

11476 2.45670819283

11477 0.405035018921

11478 2.42619085312

11479 0.392680883408

11480 2.5216550827

11481 0.401995897293







ここで、最初の数字は接続数であり、2番目は応答時間です。 これが何に関係するのか分かりません。



結論


タスクの一部として、すべての長所と短所のリストを提供します

ゲベント




ツイスト




竜巻




さて、上記のすべてから、誰もが自分で結論を出すことができます。 私は自分自身と自分のタスクにgeventを選択します。



UPD。 geventスクリプトに少し誤りがあります。 彼への負荷は少なかった。 私はそれを測定しましたが、結果は少し悪くなりましたが、最高のままでした。 サンプル結果は次のとおりです。

10336 1.01536607742 0 0 10338

10337 0.955881118774 0 0 10339

10338 0.947958946228 0 0 10340

10339 1.02578997612 0 0 10341








All Articles