Ada*_*dam 6 python sockets pygame python-2.7
嗨,我是Python的新手.我正在使用pygame模块编写一个简单的局域网游戏(对我来说并不简单).
这是问题 - 我有两台电脑(一台旧的英特尔Atom上网本,另一台英特尔i5 NTB).我想要达到至少5 FPS(上网本正在减慢NTB,但不是那么多,现在我有大约1.5 FPS),但是调用recv()函数两次主循环每次需要大约0.5秒机.wifi信号很强,路由器是300Mbit/s,它发送一个短的大约500个字符的字符串.正如你可以看到测量时间我使用time.clock().
这是"服务器"代码的一部分,我通常在i5 NTB上运行:
while 1:
start = time.clock()
messagelen = c.recv(4) #length of the following message (fixed 4 character)
if " " in messagelen:
messagelen = messagelen.replace(" ","")
message = cPickle.loads(c.recv(int(messagelen))) #list of the arrows, other player position and changes in the game map
arrowsmod = message[0]
modtankposan = message[1]
removelistmod = message[2]
for i in removelistmod:
try:
randopos.remove(i)
except ValueError:
randopossv.remove(i)
print time.clock()-start
tosendlist=[]
if len(arrows) == 0: #if there are no arrows it appends only an empty list
tosendlist.append([])
else:
tosendlist.append(arrows)
tosendlist.append([zeltankpos, 360-angle])
if len(removelist) == 0: #if there are no changes of the map it appends only an empty list
tosendlist.append([])
else:
tosendlist.append(removelist)
removelist=[]
tosend=cPickle.dumps(tosendlist)
tosendlen = str(len(tosend))
while len(tosendlen)<4:
tosendlen+=" "
c.sendall(tosendlen) #sends the length to client
c.sendall(tosend) #sends the actual message(dumped list of lists) to client
...something else which takes <0,05 sec on the NTB
Run Code Online (Sandbox Code Playgroud)
这是"客户端"游戏代码的一部分(只是颠倒了开头 - 发送/接收部分):
while 1:
tosendlist=[]
if len(arrows) == 0: #if there are no arrows it appends only an empty list
tosendlist.append([])
else:
tosendlist.append(arrows)
tosendlist.append([zeltankpos, 360-angle])
if len(removelist) == 0: #if there are no changes of the map it appends only an empty list
tosendlist.append([])
else:
tosendlist.append(removelist)
removelist=[]
tosend=cPickle.dumps(tosendlist)
tosendlen = str(len(tosend))
while len(tosendlen)<4:
tosendlen+=" "
s.sendall(tosendlen) #sends the length to server
s.sendall(tosend) #sends the actual message(dumped list of lists) to server
start = time.clock()
messagelen = s.recv(4) #length of the following message (fixed 4 character)
if " " in messagelen:
messagelen = messagelen.replace(" ","")
message = cPickle.loads(s.recv(int(messagelen))) #list of the arrows, other player position and changes in the game map
arrowsmod = message[0]
modtankposan = message[1]
removelistmod = message[2]
for i in removelistmod:
try:
randopos.remove(i)
except ValueError:
randopossv.remove(i)
print time.clock()-start
... rest which takes on the old netbook <0,17 sec
Run Code Online (Sandbox Code Playgroud)
当我在i5 NTB上运行一台机器(没有插座模块)的游戏的单人游戏版本时,它在地图的左上角有50 FPS,在右下角有25 FPS(1000x1000像素地图)包含5x5像素的正方形,我认为它因为更大的坐标而变慢,但是我不能相信这么多.在地图的右下角作为局域网游戏运行的BTW recv大约在同一时间) Atom上网本它有4-8 FPS.
那么请你告诉我,为什么它这么慢?计算机不同步,一个更快,另一个更慢,但它不能相互等待,它会延迟最多0.17秒,对吗?加上长时间的recv调用只会在更快的计算机上?另外,我不知道send/recv函数是如何工作的.这很奇怪,sendall在接收到0.5秒时几乎没有时间.也许sendall试图在后台发送,而程序的其余部分继续前进.
正如 Armin Rigo 提到的,recv将在套接字收到数据包后返回,但数据包不一定需要在调用后立即传输send。虽然send立即返回,但操作系统会在内部缓存数据,并且可能会等待一段时间以将更多数据写入套接字,然后再实际传输;这称为Nagle 算法,可避免通过网络发送大量小数据包。您可以禁用它并更快地将数据包推送到线路;尝试通过调用以下命令来启用发送TCP_NODELAY套接字上的选项(或者如果您的通信是双向的,则同时启用这两个选项):
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
Run Code Online (Sandbox Code Playgroud)
recv这可能会减少由于没有数据而导致的睡眠时间。
正如维基百科所述:
该算法与 TCP 延迟确认的交互效果很差,TCP 延迟确认是在 20 世纪 80 年代初几乎同一时间引入 TCP 的一项功能,但由不同的团队引入。启用这两种算法后,如果应用程序对 TCP 连接进行两次连续写入,然后执行读取操作,直到第二次写入的数据到达目的地后才会完成读取操作,因此会经历高达500 毫秒的恒定延迟,即“ ACK 延迟”。因此,TCP 实现通常为应用程序提供禁用 Nagle 算法的接口。这通常称为 TCP_NODELAY 选项。
您在基准测试中看到提到了 0.5 秒,因此这可能是一个原因。
| 归档时间: |
|
| 查看次数: |
8260 次 |
| 最近记录: |