- 浏览: 547792 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (618)
- java (109)
- Java web (43)
- javascript (52)
- js (15)
- 闭包 (2)
- maven (8)
- 杂 (28)
- python (47)
- linux (51)
- git (18)
- (1)
- mysql (31)
- 管理 (1)
- redis (6)
- 操作系统 (12)
- 网络 (13)
- mongo (1)
- nginx (17)
- web (8)
- ffmpeg (1)
- python安装包 (0)
- php (49)
- imagemagic (1)
- eclipse (21)
- django (4)
- 学习 (1)
- 书籍 (1)
- uml (3)
- emacs (19)
- svn (2)
- netty (9)
- joomla (1)
- css (1)
- 推送 (2)
- android (6)
- memcached (2)
- docker、 (0)
- docker (7)
- go (1)
- resin (1)
- groovy (1)
- spring (1)
最新评论
-
chokee:
...
Spring3 MVC 深入研究 -
googleyufei:
很有用, 我现在打算学学Python. 这些资料的很及时.
python的几个实用网站(转的) -
hujingwei1001:
太好了找的就是它
easy explore -
xiangtui:
例子举得不错。。。学习了
java callback -
幻影桃花源:
太好了,謝謝
Spring3 MVC 深入研究
原文地址:http://my.oschina.net/mallon/blog/224373
应用服务器的性能分析是复杂的,关注点很多。比如典型场景Web服务器+数据库,底层网络链路和网络硬件性能姑且不论,单看:Web服务器对静态文件的读写与磁盘和文件系统IO性能紧密相关;对数据的处理和数据库性能相关;而高并发访问则关系到操作系统的线程、网络套接字以及异步网络模型的效率。
在数据量大的情况下,数据库的性能成为一个至关重要的因素,随之带来Web服务器等待数据库的时间。在此基础上如果有大量的用户同时访问,那么会对Web服务器带来什么样的影响?以下主要讨论这个问题。
对于并发访问的处理,一般有两种处理机制:异步非阻塞机制、多线程阻塞机制(介绍略)。在测试选择上,前者使用基于Python的Tornado服务器,而后者使用基于Java的Tomcat服务器。注意:本文并非讨论开发语言的优劣,事实上,新版本的Java也支持异步机制,甚至高性能的epoll等。
测试工具:变态级的http_load
测试方法:使用该工具模拟1、10、100、1000个客户端并发访问以下场景,每次测试时间1分钟,得到服务器端每秒的总响应数。注意:由于Tomcat最大线程的限制(下面有提到)以及操作系统对端口数量的限制,1000个并发已经能够得到明显的结论了。
测试场景:
静态文件的读写。一个html文件和一大一小两个图片,大小分别为676k、1.6M和12k,使用http_load工具随机读取。静态文件读写的耗时可以忽略不计的。
模拟一个耗时操作,比如数据库操作。注意:耗时操作并不占用Web服务器本身的资源,它更多地体现的是Web服务器对并发访问处理的“合理”性。
以下是Java Servlet和Tornado服务的源代码:
Servlet
?
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
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name = "Dispatcher", urlPatterns = "/index")
public class index extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out = resp.getWriter();
resp.setContentType("text/plain;charset=UTF-8");
try {
// 超时设置
Thread.sleep(10000);
out.println("OK");
} catch (Exception ex) {
resp.setStatus(500);
ex.printStackTrace(out);
} finally {
out.flush();
out.close();
}
}
}
Tornado
?
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
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import logging
import os
import sys
import tornado.gen
import tornado.ioloop
import tornado.web
def log_function(handler):
pass
class IndexHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self, *args, **kwargs):
ioloop = tornado.ioloop.IOLoop.instance()
# 超时设置
ioloop.add_timeout(ioloop.time() + 10, self.done)
def done(self):
self.set_header('Content-Type', 'text/plain;charset=UTF-8')
self.write('OK')
self.finish()
log_format = '%(levelname)s %(module)s.%(funcName)s[%(lineno)d] %(message)s'
logging.basicConfig(format=log_format, level=logging.INFO)
root_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
os.chdir(root_dir)
handlers = [
('/', tornado.web.RedirectHandler, {'url': '/index.html'}),
('/index', IndexHandler),
('/(.*)', tornado.web.StaticFileHandler, {'path': ''}),
]
settings = {
'log_function': log_function,
'debug': False,
}
application = tornado.web.Application(handlers, **settings)
port = 8080
application.listen(port)
tornado.ioloop.IOLoop.instance().start()
测试结果如下:
单看数据总是云里雾里的。下面进行分析。
首先分析静态内容,如果作成图表,那么是这样的:
对于单客户端访问,两者效率相差无几,从这一点上可以看出:开发语言的效率所占的比重是微乎其微的:大凡非计算密集型的应用,IO操作总是短板,相比CPU的速度有数量级的差距。
当客户端数量增多,图表呈现出以下两个特点:
两者的每秒响应数趋稳;
Tomcat的效率大致是Tornado的3-4倍。
如果查看CPU占用:
Tomcat
Tornado
可以看到,Tomcat基本把四个核都占满了,而Tornado只占用了一个核。其中的道理其实是很清楚的:
Tomcat是多线程处理并发访问的,势必会最大限度地占用CPU,而Tornado异步机制是单线程的。
每秒处理能力还是有上限的,这就是每秒响应数趋稳的原因。如果没有缓存直接访问磁盘,那么Tomcat和Tornado的性能应该相差无几,事实上操作系统和Web服务器对文件的读写不可能没有缓存。而这个结果告诉我们在适当的线程数量范围内,文件的缓存读效率是恒定的。Tomcat和Tornado3-4倍的性能差距原因大致就在此。
静态文件的耗时非常少,所以Tomcat的每一个线程均能够很快执行完毕,线程带来的问题并不是那么明显。那么把耗时增大,会发生什么?
把程序中的延时加到1、3、10秒,每秒总响应发生了非常大的变化。此时如果再像上面静态文件分析,已经没有意义了。换一个分析方式:
把并发连接数除以服务器端每秒总响应数,可以得到单个客户端单次访问的平均时间。把这个平均时间再除以人为添加的那个延时,就得到一个比率。这个比率反映出Web服务器作为客户端和数据库(典型场景)之间的“中介”“拉皮条”的效率。这个效率的最佳值是1,如果大于1,那么就表示该“中介”把时间浪费在毫无意义的地方。
这样得到的图就很有意思了:
可以看到,100并发以内,Tomcat和Tornado的比率均在1左右;100到1000并发,Tornado继续保持1,而Tomcat在某个点之后比率就急剧增加了。这是什么原因?
如果使用VisualVM查看Tomcat的线程会发现,它的线程数达到220之后,就不再增加了:
很明显,Tomcat限制了线程数量(应该有参数可以配置的,我没有查资料)。
我没有更进一步做测试,但是可以相信,图表中Tomcat的拐点就在220处。
那么能不能一味地增加线程呢?这已经不需要我多讲了,学过操作系统的同志都知道,CPU的每一颗核上只能执行一条指令序列,线程只是CPU频繁切换造成的“假象”。随着线程的增加,切换时间占的比重将会越来越大。更多的线程除了给系统带来毫无意义的消耗没有其它任何用处。这也是Tomcat不敢把默认线程数设得太大的原因吧。
网上也有其它异步非阻塞与多线程性能的比较,这里就不转载了。
所以呢,以下就是结论了:
对并发耗时等待任务的处理,单线程异步非阻塞方式明显比无限制的阻塞多线程更“合理”,注意这里只谈合理性:用一个线程就能达到同样的效果,为什么要开多线程呢?
对非耗时任务,多线程能不能完全发挥效率也得看场景。即便IO不是短板,理论上线程数也应该低于CPU核数。
应用服务器的性能分析是复杂的,关注点很多。比如典型场景Web服务器+数据库,底层网络链路和网络硬件性能姑且不论,单看:Web服务器对静态文件的读写与磁盘和文件系统IO性能紧密相关;对数据的处理和数据库性能相关;而高并发访问则关系到操作系统的线程、网络套接字以及异步网络模型的效率。
在数据量大的情况下,数据库的性能成为一个至关重要的因素,随之带来Web服务器等待数据库的时间。在此基础上如果有大量的用户同时访问,那么会对Web服务器带来什么样的影响?以下主要讨论这个问题。
对于并发访问的处理,一般有两种处理机制:异步非阻塞机制、多线程阻塞机制(介绍略)。在测试选择上,前者使用基于Python的Tornado服务器,而后者使用基于Java的Tomcat服务器。注意:本文并非讨论开发语言的优劣,事实上,新版本的Java也支持异步机制,甚至高性能的epoll等。
测试工具:变态级的http_load
测试方法:使用该工具模拟1、10、100、1000个客户端并发访问以下场景,每次测试时间1分钟,得到服务器端每秒的总响应数。注意:由于Tomcat最大线程的限制(下面有提到)以及操作系统对端口数量的限制,1000个并发已经能够得到明显的结论了。
测试场景:
静态文件的读写。一个html文件和一大一小两个图片,大小分别为676k、1.6M和12k,使用http_load工具随机读取。静态文件读写的耗时可以忽略不计的。
模拟一个耗时操作,比如数据库操作。注意:耗时操作并不占用Web服务器本身的资源,它更多地体现的是Web服务器对并发访问处理的“合理”性。
以下是Java Servlet和Tornado服务的源代码:
Servlet
?
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
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name = "Dispatcher", urlPatterns = "/index")
public class index extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out = resp.getWriter();
resp.setContentType("text/plain;charset=UTF-8");
try {
// 超时设置
Thread.sleep(10000);
out.println("OK");
} catch (Exception ex) {
resp.setStatus(500);
ex.printStackTrace(out);
} finally {
out.flush();
out.close();
}
}
}
Tornado
?
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
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import logging
import os
import sys
import tornado.gen
import tornado.ioloop
import tornado.web
def log_function(handler):
pass
class IndexHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
def get(self, *args, **kwargs):
ioloop = tornado.ioloop.IOLoop.instance()
# 超时设置
ioloop.add_timeout(ioloop.time() + 10, self.done)
def done(self):
self.set_header('Content-Type', 'text/plain;charset=UTF-8')
self.write('OK')
self.finish()
log_format = '%(levelname)s %(module)s.%(funcName)s[%(lineno)d] %(message)s'
logging.basicConfig(format=log_format, level=logging.INFO)
root_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
os.chdir(root_dir)
handlers = [
('/', tornado.web.RedirectHandler, {'url': '/index.html'}),
('/index', IndexHandler),
('/(.*)', tornado.web.StaticFileHandler, {'path': ''}),
]
settings = {
'log_function': log_function,
'debug': False,
}
application = tornado.web.Application(handlers, **settings)
port = 8080
application.listen(port)
tornado.ioloop.IOLoop.instance().start()
测试结果如下:
单看数据总是云里雾里的。下面进行分析。
首先分析静态内容,如果作成图表,那么是这样的:
对于单客户端访问,两者效率相差无几,从这一点上可以看出:开发语言的效率所占的比重是微乎其微的:大凡非计算密集型的应用,IO操作总是短板,相比CPU的速度有数量级的差距。
当客户端数量增多,图表呈现出以下两个特点:
两者的每秒响应数趋稳;
Tomcat的效率大致是Tornado的3-4倍。
如果查看CPU占用:
Tomcat
Tornado
可以看到,Tomcat基本把四个核都占满了,而Tornado只占用了一个核。其中的道理其实是很清楚的:
Tomcat是多线程处理并发访问的,势必会最大限度地占用CPU,而Tornado异步机制是单线程的。
每秒处理能力还是有上限的,这就是每秒响应数趋稳的原因。如果没有缓存直接访问磁盘,那么Tomcat和Tornado的性能应该相差无几,事实上操作系统和Web服务器对文件的读写不可能没有缓存。而这个结果告诉我们在适当的线程数量范围内,文件的缓存读效率是恒定的。Tomcat和Tornado3-4倍的性能差距原因大致就在此。
静态文件的耗时非常少,所以Tomcat的每一个线程均能够很快执行完毕,线程带来的问题并不是那么明显。那么把耗时增大,会发生什么?
把程序中的延时加到1、3、10秒,每秒总响应发生了非常大的变化。此时如果再像上面静态文件分析,已经没有意义了。换一个分析方式:
把并发连接数除以服务器端每秒总响应数,可以得到单个客户端单次访问的平均时间。把这个平均时间再除以人为添加的那个延时,就得到一个比率。这个比率反映出Web服务器作为客户端和数据库(典型场景)之间的“中介”“拉皮条”的效率。这个效率的最佳值是1,如果大于1,那么就表示该“中介”把时间浪费在毫无意义的地方。
这样得到的图就很有意思了:
可以看到,100并发以内,Tomcat和Tornado的比率均在1左右;100到1000并发,Tornado继续保持1,而Tomcat在某个点之后比率就急剧增加了。这是什么原因?
如果使用VisualVM查看Tomcat的线程会发现,它的线程数达到220之后,就不再增加了:
很明显,Tomcat限制了线程数量(应该有参数可以配置的,我没有查资料)。
我没有更进一步做测试,但是可以相信,图表中Tomcat的拐点就在220处。
那么能不能一味地增加线程呢?这已经不需要我多讲了,学过操作系统的同志都知道,CPU的每一颗核上只能执行一条指令序列,线程只是CPU频繁切换造成的“假象”。随着线程的增加,切换时间占的比重将会越来越大。更多的线程除了给系统带来毫无意义的消耗没有其它任何用处。这也是Tomcat不敢把默认线程数设得太大的原因吧。
网上也有其它异步非阻塞与多线程性能的比较,这里就不转载了。
所以呢,以下就是结论了:
对并发耗时等待任务的处理,单线程异步非阻塞方式明显比无限制的阻塞多线程更“合理”,注意这里只谈合理性:用一个线程就能达到同样的效果,为什么要开多线程呢?
对非耗时任务,多线程能不能完全发挥效率也得看场景。即便IO不是短板,理论上线程数也应该低于CPU核数。
发表评论
-
Django静态文件处理总结
2015-05-13 13:59 506原文地址:http://blog.csdn.net/wenxu ... -
Django报错“_mysql_exceptions.Warning: Incorrect string value: ‘\xE6\xB5…’ for colu
2015-03-25 15:50 969原文地址:http://www.tuicool.com/art ... -
django使用mysql时的中文存储问题 - [python]
2015-03-25 15:36 1472原文地址:http://www.blogbus.com/831 ... -
NIO学习笔记——解决“服务器端cpu占用率高”
2015-01-29 10:17 957原文地址:http://blog.csdn ... -
python 调用 php 实例
2014-06-23 14:09 2601原文地址:http://hi.baidu.com/ji_hai ... -
php调用python
2014-06-23 14:08 767原文地址:http://blog.163.com/darwin ... -
uwsgi python ssl编译问题记录
2014-06-19 14:24 852uwsgi python ssl编译问题记录 发表于6个月前( ... -
python2.7 安装ssl模块
2014-06-19 14:22 3176python2.7 安装ssl模块 2012-02-28 13 ... -
Centos6.5下升级Python 2.6.6 to python 2.7.3
2014-06-19 13:53 636Centos6.5下升级Python 2.6.6 to pyt ... -
翻译:redis-py 说明文件 (2012-05-30 17:55:52)
2014-06-04 10:22 437翻译:redis-py 说明文件 (2012-05-30 17 ... -
关于Redis的Python客户端的连接池问题
2014-06-04 10:21 602关于Redis的Python客户端的连接池问题 在一 ... -
Windows下 Python 安装包的配置
2014-03-22 10:23 6251、下载安装 Python python-2.7.2.msi ... -
[翻译]深入理解Tornado——一个异步web服务器
2014-03-07 15:16 1610[翻译]深入理解Tornado— ... -
多版本Python共存[支持使用pip安装包]
2014-02-28 10:59 1115多版本Python共存[支持使 ... -
Django 数据库访问性能优化
2013-09-05 15:22 665Django 数据库访问性 ... -
Python六大开源框架对比:Web2py略胜一筹
2013-08-21 11:29 799Python是一门动态、面向对象语言。其最初就是作为一门面向 ... -
Python 代码调试技巧
2013-08-15 18:11 848使用 pdb 进行调试 pdb 是 python 自带的 ... -
python urlencode 编码
2013-07-05 13:28 938urlencode 调用方法 urlencode的参 ... -
window下使用virtualenv
2013-06-30 15:26 1087--- window下使用virtualenv -- ... -
浅析python的metaclass
2013-06-30 11:12 773分享下自己对python的met ...
相关推荐
用一个最简单的例子说明异步非阻塞Socket的基本原理和工作机制
使用VC++异步套接字类(AsyncSocket),进行“异步非阻塞”客户/服务器(Client/Server)网络程序设计的方法与原理。
讲述同步、异步、阻塞、非阻塞的区别,通俗易懂,是我见到的最口语话最清晰的材料,文中比喻恰当,深入浅出。
C++程序,运动MFC类库实现异步非阻塞通信。完成聊天室功能。
近期遇到界面中执行一些后台任务时界面卡死的情况,解决了在这里记录下。 PyQt PyQt简介 PyQt是Qt的python接口,PyQt的文档较少,但接口和函数可以完全参照Qt,继承了Qt中大量的控件以及信号机制,十分方便。以下...
VC连接加密wifi,异步非阻塞TCP服务端、客户端,环境为VS2013宽字节带套接字
为了给用户提供更好的体验,读取数据库等程序需要长时间来执行的操作,需要弹出一个等待界面。可以一边执行需要等待的操作,一边...本资源使用VS2017软件,VB.NET编程,异步委托和多线程编程实现背景透明的等待窗体。
多线程C语言爬虫。采用libcvent实现DNS的异步解析,使用epoll实现socket连接的非阻塞读取。
C#多线程与异步的区别详解 随着拥有多个硬线程 CPU(超线程、双核)的普及,多线程和异步操作等并发程序设计方法也受到了更多的关注和讨论。本文主要是想与各位高手一同探讨一下如何使用并发来最大化程序的性能。 ...
在异步机制中,事件是线程之间进行通信的一个非常常用的方式。比如:用户在界面上按下一个按钮,执行某项耗时的任务。程序此时启动一个线程来处理这个任务,用户界面上显示一个进度条指示用户任务执行的状态。这个...
本PDF电子书包含上下两册,共1576页,带目录,高清非扫描版本。 作者: 毛德操 胡希明 丛书名: Linux内核源代码情景分析 出版社:浙江大学出版社 目录 第1章 预备知识 1.1 Linux内核简介. 1.2 Intel X86 CPU系列...
后玩委托、 线程和异步调用的这么久,这是一种罪恶不分享我的智慧和知识对这个问题的一些因此希望,你 won�t 找一个 MSDN 文章在 1 AM 不知道为什么在你决定去到计算机。 我会尝试使用婴儿步骤和大量的 examples�...
通过多线程处理大批量耗时业务,并返回结果。当监测到线程池中存在空闲线程时则动态向线程池中添加新的任务,直到所有任务执行结束。Demo为自己写的测试使用,下载后可直接运行测试。
同步异步,阻塞非阻塞,I/O学习总结的思维导图,需要结合Richard Stevens的书来学习
Android多线程及异步任务消息处理机制 一 Handler的使用博文源代码 想要学习更多有关于Android的知识 请关注博客http: blog csdn net yegongheng
C#语言,运用TCP异步收发信息。客户端只要知道服务器端IP和端口号,就可以和服务器建立连接,异步收发信息。本实例包括服务器端和客户端程序,并且有很详细的注释,希望大家看后能有一定的收获。
vc++ 线程同步与异步套接字编程实例,Windows套接字在两种模式下执行I/O操作,阻塞和非阻塞。在阻塞模式下,在I/O操作完成前,执行操作的Winsock函数会一直等待下去,不会立即返回程序(将控制权交还给程序)。而在非...
http://www.cnblogs.com/itbird/archive/2010/01/19/1651322.html 文章中涉及到得源码,开始时始终是无法编译通过的。 经过翻阅资料并修改后,能正常运行。
本程序详细介绍了线程和线程池的用法,使用多线程进行和异步编程实现数据库操作和日志的记录
采用STM32F103C8T6单片机,KeilMDK5.32版本 串口异步通信,开启收发方向,阻塞式发送(仿printf发送);...在接收完成回调函数中,重新开启接收中断(因为在进入接收回调函数前,所有与接收相关的中断已经关闭)