我们的业务代码就是
counter = 0 if __name__ == '__main__': def logic(d_in): global counter counter += 1 if counter %100000 ==0: print counter,time.time() return(d_in[::-1]) reverseD = nbNet('0.0.0.0', 9099, logic) reverseD.run()
说白了就是 每响应10w下答应一下时间
我们测试端代码
#!/usr/bin/env python import socket, sys, os HOST = '127.0.0.1' PORT = 9099 CNT = int(sys.argv[2]) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) cmd = sys.argv[1] data = "%010d%s"%(len(cmd), cmd) while True: s.send(data * CNT) s.recv(len(data) * CNT)
但是我们的客户端是不可能打到server端的性能瓶颈的,我们可以开启多个终端,启动多个实例,这样达到我们性能要求
我们首先看下没有优化之前的性能
我们虚拟机的性能是:一核心CPU没有超线程 2.5G 内存2G
我们从300w次请求之后选取后面100w次的时间
3000000 1527159028.98
3100000 1527159031.62
3200000 1527159034.16
3300000 1527159036.72
3400000 1527159039.27
3500000 1527159041.82
3600000 1527159044.38
3700000 1527159047.01
3800000 1527159049.56
3900000 1527159052.12
4000000 1527159054.69
我们计算下每10w次请求的时间(取小数点后两位)
[0] 2.63s
[1] 2.54s
[2] 2.56s
[3] 2.55s
[4] 2.56s
[5]2.62s
[6] 2.55s
[7] 2.56s
[8] 2.57s
[9]2.56s
最差 2.63s QPS 约等于 38022
最好 2.54s QPS 约等于 39370
==============================================================
在python内建了一个 profiler工具,可以帮我们定位性能瓶颈
服务端调用方法
python -m cProfile -s cumulative nbNetFramework.py -s cumulative 的意思是按照系统调用的总体耗时排序
客户端调用方法
python loadrun.py a 100
python loadrun.py a 100
执行一段时间后 结束server的时候会输出这段时间代码中的方法执行时间情况
root@work:/home/rico/python/rebootMon/nbNet# python -mcProfile -s cumulative nbNetFramework.py 100000 1527160075.61 200000 1527160079.19 300000 1527160082.8 ^C 11986059 function calls (11985241 primitive calls) in 14.675 seconds Ordered by: cumulative time ncalls tottime percall cumtime percall filename:lineno(function) 1 0.001 0.001 14.675 14.675 nbNetFramework.py:4(<module>) 1 1.693 1.693 14.654 14.654 nbNetFramework.py:166(run) 1088050 0.615 0.000 10.292 0.000 nbNetFramework.py:192(state_machine) 725366 0.622 0.000 5.588 0.000 nbNetFramework.py:271(read2process) 362683 0.670 0.000 4.089 0.000 nbNetFramework.py:307(write2read) 725366 1.722 0.000 2.981 0.000 nbNetFramework.py:66(read) 1088050 2.669 0.000 2.669 0.000 {method 'poll' of 'select.epoll' objects} 362683 1.209 0.000 1.985 0.000 nbNetFramework.py:232(process) 362683 0.605 0.000 1.691 0.000 nbNetFramework.py:124(write) 362685 0.719 0.000 1.382 0.000 nbNetFramework.py:21(setFd) 725366 1.070 0.000 1.070 0.000 {method 'recv' of '_socket.socket' objects} 362683 0.894 0.000 0.894 0.000 {method 'send' of '_socket.socket' objects} 725365 0.740 0.000 0.740 0.000 {method 'modify' of 'select.epoll' objects} 362692 0.303 0.000 0.423 0.000 socket.py:227(meth) 362683 0.320 0.000 0.320 0.000 nbNetFramework.py:339(logic) 2905468/2905319 0.250 0.000 0.250 0.000 {len} 362685 0.240 0.000 0.240 0.000 nbNetUtils.py:164(__init__) 363892 0.192 0.000 0.192 0.000 {isinstance} 362725 0.067 0.000 0.067 0.000 {getattr} 362688 0.053 0.000 0.053 0.000 {method 'fileno' of '_socket.socket' objects
ncalls -- 调用多少次
#自己调用的时间,不包括其他十年
tottime 调用时耗
percall 每次调用的时间
#包括子函数时间
cumtime调用耗时
percall 每次调用耗时
这样我们就知道那个方法比较耗费时间了。
然后通过 line_profiler来优化具体的行
#pip install line_profiler 安装
在比较耗时的方法上面加上@profile 这个装饰(这里我们看到之前的read方法比较耗时)
# kernprof -l -v ./nbNet.py 执行命令
然后我们执行客户端代码
然后等一段时间结束
Function: read at line 45 Line # Hits Time Per Hit % Time Line Contents ============================================================== 45 @profile 46 def read(self, fd): 47 """fd is fileno() of socket""" 48 87910 118605.0 1.3 7.1 try: 49 87910 104105.0 1.2 6.2 sock_state = self.conn_state[fd] 50 87910 71153.0 0.8 4.2 conn = sock_state.sock_obj 51 87910 79448.0 0.9 4.7 if sock_state.need_read <= 0: 52 raise socket.error 53 87910 433116.0 4.9 25.8 one_read = conn.recv(sock_state.need_read) 54 87910 118447.0 1.3 7.1 if len(one_read) == 0: 55 raise socket.error 56 87910 122770.0 1.4 7.3 sock_state.buff_read += one_read 57 87910 92267.0 1.0 5.5 sock_state.have_read += len(one_read) 58 87910 99366.0 1.1 5.9 sock_state.need_read -= len(one_read) 59 60 61 87910 78578.0 0.9 4.7 if sock_state.have_read == 10: 62 43955 126373.0 2.9 7.5 header_said_need_read = int(sock_state.buff_read) 63 43955 41639.0 0.9 2.5 if header_said_need_read <= 0: 64 raise socket.error 65 43955 45788.0 1.0 2.7 sock_state.need_read += header_said_need_read 66 43955 39130.0 0.9 2.3 sock_state.buff_read = '' 67 43955 33228.0 0.8 2.0 return "readcontent" 68 43955 37326.0 0.8 2.2 elif sock_state.need_read == 0: 69 43955 35561.0 0.8 2.1 return "process" 70 else: 71 return "readmore" 72 except (socket.error, ValueError), msg: 73 try: 74 if msg.errno == 11: 75 return "retry" 76 except: 77 pass 78 return 'closing'