0%

注意

  • 此次实践的jmeter版本不能过高,建议用3.1
  • 大量性能压测时,不介意使用此教程,此次实践只为简单练手

下载插件

准备

  • 首先把解压出来的JMeterPlugins-Standard.jarJMeterPlugins-Extras.jar两个jar包放在apache-jmeter\lib\ext目录下

    image-20211014103834047

  • 重新启动jmeter之后可以看到监听器里多了许多jp@gc开头的就成功了

    image-20211014103940321

    image-20211014104308298

  • Agent方面,只需要将ServerAgent在目标机器上启动即可。比如win上直接打开bat文件即可

    image-20211014104201505

    查看监控效果

  • 运行脚本,查看效果

    image-20211014104558450

环境

  • jmeter version 5.4.1
  • Badboy录制了三个步骤
    • 登录
    • 打开用户列表
    • 新增用户

问题点

  • Badboy录制后的脚本给jmeter打开,直接是无法运行的,需要做如下配置

设置jmeter代理

image-20211009150800398

  • 设置代理后,登录接口出错,发现传参应该为json但是传的是

image-20211009153859635

  • 改为放到body data中放json

    image-20211009154035718

  • 设置代理后,登录接口抱错,抓包登录接口发现是header的Accept设置错误,设置加了个applicaiton/json

    image-20211009151254512

    登录后的设置

  • 再次回放,登录成功了,但是登录后的其他接口一直返回403,因为所有接口的头部加了Authorization 验证,在登录接口设置后置处理器json提取器

  • 查看登录接口返回的数据

    image-20211009151904817

  • 新建后置处理器json提取器

    image-20211009152109721

  • 设置提取Authorization的值

    image-20211009152223210

  • HTTP Header设置请求参数

    image-20211009152326586

结论

  • 最终回放成功

    image-20211009152629801

修正

  • 2021年10月28日,无法回放和jmeter设置的代理无关,设置代理后可以直接用来录制,后续会有笔记对这个进行说明

  • 打开chrome浏览器的调试工具,如图所示:

image.png

主要看下这里的Finish,DOMLoadedLoad的区别

DOMLoadedLoad

  • DOMContentLoaded Load 分别对应 页面 DOMContentLoadedLoad 事件触发的时间点
  • DOMContentLoadedDOM树构建完成。即HTML页面由上向下解析HTML结构到末尾封闭标签</html>
  • Load:页面加载完毕。 DOM树构建完成后,继续加载html/css 中的图片资源等外部资源,加载完成后视为页面加载完毕。
  • DOMContentLoaded 会比 Load 时间小,两者时间差大致等于外部资源加载的时间。
    看看下面这个例子:
1
2
3
4
5
6
<html>
<script src=1.js></script>
<script src=2.js></script>
<img src=1.jpg />
<script src=3.js></script>
</html>
  • 3.js 执行(不包括异步部分)后,后面的 html 才能允许渲染, DOMContentLoaded 应该是指 最后一个字节都被渲染出来后的时间 (onDocumentChange 状态变成 ready )。而 onLoad 的触发除了dom还包括所有依赖元素,上例中就是要等 1.jpg 加载完成(或出错)后才能触发

看下Finish

  • Chrome devtools中的Finish时间似乎包括页面上的异步加载(非阻塞)对象/元素,这些对象/元素可能会在页面的onload事件触发后继续下载。
  • 一般来说,网站的响应时间意味着Load时间,因为用户可以更容易地感知到这一点,此时用户可以看到浏览器已完成工作并且页面已准备就绪。
  • 在某些情况下,似乎Finish永远不会停止并继续增加,因此它可能不是对网页响应时间的最佳评估。
  • 经过测试会出现会出现Finish 的时间比 Load 大也有可能小,引用于这篇文章

    Finish 时间与DOMContentLoaded 和 Load 并无直接关系。
    Finish 时间是页面上所有 http 请求发送到响应完成的时间,HTTP1.0/1.1 协议限定,单个域名的请求并发量是 6 个,即Finish是所有请求(不只是XHR请求,还包括DOC,img,js,css等资源的请求)在并发量为6的限制下完成的时间。
    Finish 的时间比 Load 大,意味着页面有相当部分的请求量,
    Finish 的时间比 Load 小,意味着页面请求量很少,如果页面是只有一个 html文档请求的静态页面,Finish时间基本就等于HTML文档请求的时间
    页面发送请求和页面解析文档结构,分属两个不同的线程,

实践列子

  • 看看官网的例子
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import PyChromeDevTools
    import time
    import os
    os.chdir(r"C:\Users\Administrator\AppData\Local\Google\Chrome\Application")
    cmd = "chrome.exe --remote-debugging-port=9222"
    os.popen(cmd)
    chrome = PyChromeDevTools.ChromeInterface()
    chrome.Network.enable()
    chrome.Page.enable()
    chrome.Page.reload(ignoreCache=True) # 不带缓存
    start_time=time.time()
    chrome.Page.navigate(url="http://www.baidu.com/")
    chrome.wait_event("Page.loadEventFired", timeout=60)
    end_time = time.time()
    print("Page Loading Time:", end_time-start_time)
    chrome.close()

得到结果为:

1
2
3
Page Loading Time: 1.702894687652588
Page Loading Time: 1.658094882965088
Page Loading Time: 1.5752882957458496

在chrome浏览器的console下调试,基本上和load时间一致:
image.png

在chrome 浏览器里调试

  • Console输入 window.performance.getEntries(),可以看到页面上所有的资源请求,不统计404的请求
    image.png

  • 有65个请求,里面有请求的哪个节点耗时,和url,查看第一个请求duration其实就是页面的load时间
    image.png
    image.png

  • 想过把这所有资源的duration相加应该就能得到Finish时间?,经过测试,当然是不行的,第一个请求duration虽然是页面的load时间,但是它可能包含了页面上的非异步的请求,同时也包含了css,img,dom的加载时间,因此相加统计肯定会被Finish要大

关于自动化

  • 可以结合selenium来使用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from selenium import webdriver
    import os
    PATH = lambda p: os.path.abspath(
    os.path.join(os.path.dirname(__file__), p)
    )
    chrome_driver = PATH("exe/chromedriver.exe")
    os.environ["webdriver.chrome.driver"] = chrome_driver
    driver = webdriver.Chrome(chrome_driver)
    driver.get("http://www.baidu.com")
    data = driver.execute_script("return window.performance.getEntries();")
    print(data)

移动端h5性能测试

  • 打开手机usb调试
  • 如果是想调试混合app的webview,请打开:
    1
    2
    3
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    MtcWebView.setWebContentsDebuggingEnabled(true);
    }
  • 手机连接电脑后,打开chrome,输入chrome://inspect/#devices
  • 然后就可以进行调试了
    image.png

image.png
image.png

扩展阅读

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import pandas as pd
from ast import literal_eval


class OperateExcel():
def __init__(self, file_path):
self.file_path = file_path
self.df = pd.read_excel(file_path, sheet_name="Sheet1") # sheet_name不指定时默认返回全表数据
# self.df = pd.read_excel(file_path, sheet_name="Sheet1", usecols=['name', 'method'])

def get_excel(self):
"""
读取表格数据存为json
:return:
"""

data = []
for i in self.df.values:
params = ""
if i[3] == "post":
params = literal_eval(i[4])
app = {"id": i[0], "name": i[2], "method": i[3], "params": params}
data.append(app)
print(data)

def write_excel(self):
# 根据条件累加数据
self.df['id'][self.df['name'] == '测试2'] += 100
print(self.df.head())
self.df.to_excel('data3.xlsx', sheet_name='Sheet1', index=False, header=True)

# 新增一行
self.df.loc[10] = [5, 'Eric', 'male', 20, '']

# 新增一列
self.df['favorite'] = None

self.df.to_excel('data3.xlsx', sheet_name='Sheet1', index=False, header=True)
print(self.df.head())

def get_filter_excel(self):
# 查看所有的值
print(self.df.values)

# 查看第一行的值
print(self.df.values[0])

# 查看某一列所有的值
print(self.df['name'].values)
print("===打印头部数据,仅查看数据示例时常用====")
print(self.df.head())
print("====打印列标题===")
print(self.df.columns)
print("====打印行========")
print(self.df.index)
print("========打印指定列============")
print(self.df["name"])


if __name__ == "__main__":
file_path = 'data3.xlsx'
o_excel = OperateExcel(file_path)
o_excel.get_excel()
# o_excel.write_excel()
# o_excel.get_filter_excel()

  • excel文件内容

image.png

  • 其他几款操作excel对比,图片来源这里
    image.png

python3.x已经把md5 module移除了。要想用md5得用hashlib module,

1
2
3
4
5
import hashlib  
m = hashlib.md5()
m.update(b"Nobody inspects the spammish repetition") #参数必须是byte类型,否则报Unicode-objects must be encoded before hashing错误
md5value=m.hexdigest()
print(md5value) #bb649c83dd1ea5c9d9dec9a18df0ffe9

其实可简写,如下面的md5的例子,hashlib.md5(data),就可以了

但是对中文字符串md5怎么办?
中文字符在Python中是以unicode存在的,同一个字符串在不同的编码体系下有不同的值,所以在hash前要进行编码,个人建议转为gb2312,因为对比发现,我下载的一个工具算出的md5值是与gb2312编码后算出的md5值一样。

1
2
3
4
import hashlib  
data='我是'
m = hashlib.md5(data.encode(encoding='gb2312'))
print(m.hexdigest())

  • python socket server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import socket

try:
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
print("create socket succ!")

sock.bind(('192.168.1.38',50006))
print('bind socket succ!')

sock.listen(5)
print('listen succ!')

except:
print("init socket error!")

while True:
print("listen for client...")
conn,addr=sock.accept()
print("get client")
print(addr)

conn.settimeout(30)
szBuf=conn.recv(1024)
print("recv:"+str(szBuf,'gbk'))

if "0"==szBuf:
conn.send(b"exit")
else:
conn.send(b"welcome client")

conn.close()
print("end of servive")


  • python socket client
1
2
3
4
5
6
7
8
9
10
11
12
13
import socket
HOST = '192.168.1.38'
PORT = 50006

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
sock.send("232132132131".encode())

szBuf = sock.recv(1024)
byt = 'recv:' + szBuf.decode('utf-8')
print(byt)

sock.close()
  • java socket client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;


public class SocketClient {

public static void main(String args[])throws Exception {

try {
Socket socket = new Socket("192.168.1.38",50006);

//获取输出流,向服务器端发送信息
OutputStream os=socket.getOutputStream();//字节输出流
PrintWriter pw=new PrintWriter(os);//将输出流包装为打印流
pw.write("我是Java服务器");
pw.flush();
socket.shutdownOutput();//关闭输出流

InputStream is=socket.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(is));
String info=null;
while((info=in.readLine())!=null){
System.out.println("我是客户端,Python服务器说:"+info);
}
is.close();
in.close();
socket.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
  • 值得注意的是,这里的服务器域名应该写本电脑上的ip,而不是127.0.0.1

来自: http://blog.csdn.net/ChenTianSaber/article/details/52274257?locationNum=4

  • 单线程,多线程下载某云音乐
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import re
import urllib.request
import requests
from bs4 import BeautifulSoup
import os
import time
from Threads import BaseThread

PATH = lambda p: os.path.abspath(
os.path.join(os.path.dirname(__file__), p)
)

'''
https://music.163.com/playlist?id= 得到播放列表
http://music.163.com/song/media/outer/url?id= 得到下载链接
urllib.request.urlretrieve 把远程下载的mp3文件下载到本地
'''


class Music163:
def __init__(self):
pass
def get_music_163(self, id):
user_agent = 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 ' \
'Safari/537.36 '
headers = {'User-Agent': user_agent}
data = requests.get("https://music.163.com/playlist?id=" + id, headers).text
soup = BeautifulSoup(data, 'lxml')
temp = []
for i in soup.find("ul", {"class", "f-hide"}).find_all("a"):
pattern = re.compile('<a .*?id=(.*?)">(.*?)</a>', re.S)
items = re.findall(pattern, str(i))
temp.append([items[0][0], items[0][1]])
return temp

# 批量下载
def download(self, value):
for i in value:
if os.path.isfile(PATH("mp3/" + i[1] + ".mp3")):
print("%s已经被下载了" % i[1])
else:
url = 'http://music.163.com/song/media/outer/url?id=' + i[0] + '.mp3'
urllib.request.urlretrieve(url, '%s' % PATH("mp3/" + i[1] + ".mp3"))
print("%s下载成功" % i[1])

# 单个下载
def get(self, value):
if os.path.isfile(PATH("mp3/" + value[1] + ".mp3")):
print("%s已经被下载了" % value[1])
else:
url = 'http://music.163.com/song/media/outer/url?id=' + value[0] + '.mp3'
urllib.request.urlretrieve(url, '%s' % PATH("mp3/" + value[1] + ".mp3"))
print("%s下载成功" % value[1])


# 多线程
def multi_thread():
id = "2786226719" # 播放的列表id
start_time = time.time()
threads = []
mc = Music163()
data = mc.get_music_163(id)
count = len(data)
for i in range(0, count):
threads.append(BaseThread(mc.get(data[i])))
for j in range(0, count):
threads[j].start()
for k in range(0, count):
threads[k].join()
end_time = time.time()
print("共耗时%.2f" % (end_time - start_time) + "秒")
# 多线程47秒


# 运行单线程
def run():
id = "2786226719" # 播放的列表id
start_time = time.time()
mc = Music163()
data = mc.get_music_163(id)
mc.download(data)
end_time = time.time()
print("共耗时%.2f" % (end_time - start_time) + "秒")
# 单线程43秒


if __name__ == "__main__":
# run()
multi_thread()
  • 单线程共下载100首歌,耗时9.09秒

dan.png

  • 多线程共下载100首歌,耗时9.60秒

image.png

  • 协程下载的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
mport time
from multiprocessing import Process
from gevent import monkey
import urllib.request
import BaseMusic163
monkey.patch_all()
import gevent
import os

PATH = lambda p: os.path.abspath(
os.path.join(os.path.dirname(__file__), p)
)
'''
协程发请求,
'''
class Producer(object):
def __init__(self):
self._rungevent()

def _rungevent(self):
jobs = []
id = "2786226719" # 播放的列表id
start_time = time.time()
mc = BaseMusic163.Music163()
data = mc.get_music_163(id)
count = len(data)
for i in range(count): # windows下有1024端口限制
jobs.append(gevent.spawn(self.produce(data[i])))
gevent.joinall(jobs)
end_time = time.time()
print("共耗时%.2f" % (end_time - start_time) + "秒")

def produce(self, value):
if os.path.isfile(PATH("mp3/" + value[1] + ".mp3")):
print("%s已经被下载了" % value[1])
else:
url = 'http://music.163.com/song/media/outer/url?id=' + value[0] + '.mp3'
urllib.request.urlretrieve(url, '%s' % PATH("mp3/" + value[1] + ".mp3"))
print("%s下载成功" % value[1])


def main():
p1 = Process(target=Producer, args=())
p1.start()


if __name__ == '__main__':
main()
  • 下载时间
    image.png

结论

  • 昨天测试,发现是协程>多线程>单线程
  • 今天测试却是:多线程>协程>单线程
  • 当然也会出现单线程耗时反而比多线程耗时短的情况
  • 一直流传多进程+协程,可以解决python的GIL问题,因为本次测试的数据不多,使用的也是单进程+协程的方式,后续对协程的测试,有机会进行大量数据的测试,采用多进程+协程的方式进行测试
  • 源码获取

开放端口

1
2
3
4
5
6
7
8
firewall-cmd --zone=public --add-port=8100/tcp --permanent
firewall-cmd --reload # 配置立即生效
firewall-cmd --zone=public --list-port # 查看防火墙所有开放的端口
firewall-cmd --state # 查看防火墙状态
netstat -lnpt # 查看监听的端口
netstat -lnpt |grep 5672 # 查看监听的具体端口


  • 编写和启动脚本start.sh,启动sh start.sh
    1
    2
    3
    4
    5
    # 后台启动django服务,输出日志到日志文件中,内容为标准输出和标准错误
    MYDATE=`date +%Y%m%d`
    ALL_LOGFILE=/usr/local/log/log_$MYDATE

    nohup python3 manage.py runserver 0.0.0.0:8100 > ${ALL_LOGFILE} 2>&1 &

按照nginx

  • 按照依赖文件

    1
    2
    3
    4
    5
    yum install gcc-c++
    yum install -y pcre pcre-devel
    yum install -y zlib zlib-devel
    yum install -y openssl openssl-devel

  • 配置nginx

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    wget -c https://nginx.org/download/nginx-1.10.1.tar.gz
    tar -zxvf nginx-1.10.1.tar.gz
    cd nginx-1.10.1
    ./configure # 使用默认配置
    # 编辑安装
    make
    make install

    whereis nginx # 查询安装路径
    # 启动、停止nginx
    cd /usr/local/nginx/sbin/
    ./nginx # 启动
    ./nginx -t # 检查
    ./nginx -s stop
    ./nginx -s quit
    ./nginx -s reload
  • 修改配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    vim nginx.conf



    #user nobody;
    worker_processes 1;

    #error_log logs/error.log;
    #error_log logs/error.log notice;
    #error_log logs/error.log info;

    #pid logs/nginx.pid;

    events {
    worker_connections 1024;
    }

    http {
    include mime.types;
    default_type application/octet-stream;

    #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
    # '$status $body_bytes_sent "$http_referer" '
    # '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log logs/access.log main;

    sendfile on;
    #tcp_nopush on;

    #keepalive_timeout 0;
    keepalive_timeout 65;

    #gzip on;
    #upstream表示负载服务器池,定义名字为goserver的服务器池
    #upstream goserver {
    # server 47.123.15.125:8887 weight=7;
    # server 192.111.50.133:8888 weight=3;
    #}
    #基于域名的虚拟主机
    server {
    #8880为监听端口号
    listen 8880;
    server_name 192.168.111.128;
    index index.html index.htm;
    #root 是你的访问目录
    root /home/dist;
    #charset koi8-r;

    #access_log logs/host.access.log main;

    #error_page 404 /404.html;

    # redirect server error pages to the static page /50x.html
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    root html;
    }

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    # root html;
    # fastcgi_pass 127.0.0.1:9000;
    # fastcgi_index index.php;
    # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
    # include fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    # deny all;
    #}
    }
    }


  • 关掉防火墙的端口

    1
    2
    3
    4
    5
    //8088,自己指定端口
    firewall-cmd --permanent --add-port=8880/tcp --zone=public
    //重新加载
    firewall-cmd --reload

  • 重启nginx

    1
    2
    3
    4
    5
    //检查配置是否正确
    ./nginx -t
    //启动nginx
    ./nginx

  • 前台正常访问
    image.png

局限性。

  • Monkey测试使用的事件流数据流是随机的,不能进行自定义。
  • 可对MonkeyTest的对象,事件数量,类型,频率等进行设置。

Monkey的基本用法

  • 基本语法如下:
    • $ adb shell monkey [options]
    • 如果不指定options,Monkey将以无反馈模式启动,并把事件任意发送到安装在目标环境中的全部包。下面是一个更为典型的命令行示例,它启动指定的应用程序,并向其发送500个伪随机事件:
    • $ adb shell monkey -p your.package.name -v 500

分析日志

  • 通过Android trace文件分析死锁ANR实例过程
  • system/build.prop 日志文件主要记录手机系统信息,如版本,型号,品牌
  • adb logcat 导出日志文件

monkey.ini 配置文件

1
2
3
4
5
6
7
8
cmd=adb shell monkey -p com.dgm.user --throttle 500 --ignore-timeouts --ignore-crashes   --monitor-native-crashes -v -v
package_name=com.dgm.user
logdir=d:\android
remote_path=d:\android_server
phone_msg_log=d:\android_temp\phone.txt
sum = 100 -
activity = com.dgm.user.SplashActivity
exceptions=['NullPointer','IllegalState','IllegalArgument','ArrayIndexOutOfBounds','RuntimeException','SecurityException']
  • throttle 每次事件等待500毫秒
  • sum 定义随机事件数
  • exceptions 异常定义,用于后面扩展

结果生成为可视化图片 使用的是matplotlib

image-20210930181002746

  • 当然可以看日志文件

代码分析

  • 获得cpu-men
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# -*- coding: utf-8 -*-
import subprocess
pkg_name = "com.dgm.user"
cpu = []
men = []
def top_cpu(pkg_name):
cmd = "adb shell dumpsys cpuinfo | grep " + pkg_name
temp = []
# cmd = "adb shell top -n %s -s cpu | grep %s$" %(str(times), pkg_name)
top_info = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.readlines()
for info in top_info:
temp.append(info.split()[2].decode()) # bytes转换为string
# print("cpu占用:%s" %cpu)
for i in temp:
if i != "0%":
cpu.append(i.split("%")[0])
return cpu

def get_men(pkg_name):
cmd = "adb shell dumpsys meminfo %s" %(pkg_name)
print(cmd)
temp = []
m = []
men_s = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.readlines()
for info in men_s:
temp.append(info.split())
# print("内存占用:%s" %men[19][1].decode()+"K")
m.append(temp)
for t in m:
men.append(t[19][1].decode())
return men
  • 入口代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import monkeyConfig
from adb_common import AndroidDebugBridge as ai
import matplotlibBase as mt
import MenCpu as m
import datetime as dt
CPU = [[],[]] # time,使用情况
MEN = [[],[]] #当前时间,和内存使用情况
# 得到手机信息
def getPhoneMsg(cmd_log):
l_list = []
f = open(cmd_log, "r")
lines = f.readlines()
for line in lines:
line = line.split('=')
#Android 系统,如anroid 4.0
if (line[0] == 'ro.build.version.release'):
l_list.append(line[1])
#手机名字
if (line[0]=='ro.product.model'):
l_list.append(line[1])
#手机品牌
if (line[0]=='ro.product.brand'):
l_list.append(line[1])
f.close()
return l_list

#开始脚本测试
def start_monkey(cmd, logdir, now1, logcatname):
print(cmd)
os.popen(cmd)
# os.kill()
#print"使用Logcat导出日志"
cmd2 = "adb logcat -d >%s" % logcatname
os.popen(cmd2)
#print"导出traces文件"
tracesname = logdir + "\\" + now1 + r"traces.log"
cmd3 = "adb shell cat /data/anr/traces.txt>%s" % tracesname
os.popen(cmd3)

if __name__ == '__main__':
ini_file = 'monkey.ini'
if os.path.isfile(ini_file):
if ai().attached_devices():
mc = monkeyConfig.baseReadnin(ini_file)
ai().open_app(mc.get_package_name(), mc.get_activity())
os.system('adb shell cat /system/build.prop >'+mc.get_phone_msg_log()) #存放的手机信息
ll_list = getPhoneMsg(mc.get_phone_msg_log())
# monkey开始测试
sum = mc.get_sum()
temp = ""
monkeylog = ""
start_monkey(mc.get_cmd(), mc.get_logdir(), mc.get_now(), mc.get_logcatname())
for i in range(sum):
time.sleep(1)
print(i)
dn = dt.datetime.now()
CPU[0].append(dn)
m.top_cpu(mc.get_package_name())
MEN[0].append(dn)
m.get_men(mc.get_package_name())
monkeylog = open(mc.get_logdir() + "\\" + mc.get_now()+"monkey.log")
temp = monkeylog.read()
monkeylog.close()
if temp.count('Monkey finished')>0:
print("测试完成咯")
CPU[1].append(m.cpu)
MEN[1].append(m.men)
# geterror(ll_list, mc.get_log(), mc.get_remote_path(), mc.now) 错误显示
mt.cpu_men_plots(CPU, MEN)
break
else:
print("设备不存在")
else:
print(u"配置文件不存在"+ini_file)
  • 结果以曲线图展示
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    def cpu_men_plots(cpu, men):
    import matplotlib.pyplot as pl
    import matplotlib.dates as mdates
    import datetime

    # 处理异常数据,有时候得到数据(占用情况)会比时间多一次循环的数据,造成xy的数据不一致,而引起报错
    if len(cpu[0]) != len(cpu[1][0]):
    cpu[1][0]= cpu[1][0][0:len(cpu[0])]

    if len(men[0]) != len(men[1][0]):
    men[1][0]= men[1][0][0:len(men[0])]
    print(men[0])
    print(men[1][0])
    a1 = pl.subplot(311)
    a1.set_title("CPU")
    a1.set_ylabel("占用情况%")
    a1.plot(cpu[0], cpu[1][0])
    a1.xaxis.set_major_locator(mdates.SecondLocator(interval=1))
    a1.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))

    a2 = pl.subplot(312)
    a2.set_title("内存")
    a2.set_ylabel("使用情况 K")
    a2.plot(men[0], men[1][0])
    a2.xaxis.set_major_locator(mdates.SecondLocator(interval=2))
    a2.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))

    # a3 = pl.subplot(313)
    # a3.set_title("流量")
    # a3.set_ylabel("使用情况 K")
    # a3.plot(x,list2)
    # a3.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))

    # a1.margins(x=0.2)
    pl.tight_layout()
    pl.show()

更多请参考我的源码

例子一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import asyncio
from aiohttp import ClientSession
#  你使用async以及await关键字将函数异步化
async def fetch(url):
async with ClientSession() as session:
async with session.get(url) as response:
return await response.read()
async def run(loop, r):
url = "http://gc.ditu.aliyun.com/geocoding?a=苏州市"
tasks = []
for i in range(r):
task = asyncio.ensure_future(fetch(url.format(i)))
tasks.append(task)

responses = await asyncio.gather(*tasks)
# 注意asyncio.gather()的用法,它搜集所有的Future对象,然后等待他们返回。
# print(json.loads(responses[0].decode()))
print(len(responses))

loop = asyncio.get_event_loop()
future = asyncio.ensure_future(run(loop, 800))
loop.run_until_complete(future)

  • future = asyncio.ensure_future(run(loop, 800)) 这里 构造1000个请求时,就报too many open files loop is not close 作者也遇到此问题,说是本机的socket 端口用光了?很是怀疑

例子二 asyncio.Semaphore解决报错问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import asyncio
from aiohttp import ClientSession

async def fetch(url):
async with ClientSession() as session:
async with session.get(url) as response:
return await response.read()


async def bound_fetch(sem, url):
async with sem:
await fetch(url)

async def run(loop, r):
url = "http://gc.ditu.aliyun.com/geocoding?a=苏州市"
tasks = []
# create instance of Semaphore
sem = asyncio.Semaphore(100)
for i in range(r):
# pass Semaphore to every GET request
task = asyncio.ensure_future(bound_fetch(sem, url.format(i)))
tasks.append(task)

responses = await asyncio.gather(*tasks)
print(responses)
number = 100000
loop = asyncio.get_event_loop()

future = asyncio.ensure_future(run(loop, number))
loop.run_until_complete(future)
  • 然而我用asyncio.Semaphore时,发现请求不成功,已经发了邮件给作者,没有回我。