linux多线程磁盘io可以同时写磁盘吗

性能测试瓶颈定位——磁盘IO和线程切换过多
性能测试瓶颈定位——磁盘IO和线程切换过多
近期在一个性能测试项目中遇到了一个调优的过程。分享一下给大家。
1、&第一次打压时,发现A请求压力80tps后,cpu占用就非常高了(24核的机器,每个cpu占用率全面飙到80%以上),且设置的检查点没有任何报错。
2、&了解了一下后台实现逻辑:大体是这样的:服务器接到请求后,会再到另一台kv服务器请求数据,拿回来数据后,根据用户的机器码做个性化运算,最后将结果返回给客户端,期间会输出一些调试log。
查了下,kv服务器正常,说明是本机服务服务器的问题。具体用vmstat命令看一下异常的地方。
3、&从图中可以直观的看出,bi、bo、in、cs这四项的值都很高,根据经验,bi和bo代表磁盘io相关、in和cs代表系统进程相关。一个一个解决吧,先看io。
4、&用iostat –x命令看了下磁盘读写,果然,磁盘慢慢给堵死了。
5、&看了下过程,只有写log操作才能导致频繁读写磁盘。果断关闭log。重新打压试下。
6、&Bi和bo降到正常值了,说明磁盘的问题解决了。但是上下文切换数竟然达到了每秒40万次!好可怕~
7、&只知道上下文切换数很大,怎么知道是在哪些进程间切换呢?
到网上搜了一个脚本,这个脚本用来统计特定时间内进程切换的top20并打印出来。
#! /usr/bin/env stap
global csw_count
global idle_count
probe scheduler.cpu_off {
csw_count[task_prev, task_next]++
idle_count+=idle
function fmt_task(task_prev, task_next)
return sprintf(&%s(%d)-&%s(%d)&,
task_execname(task_prev),
task_pid(task_prev),
task_execname(task_next),
task_pid(task_next))
function print_cswtop () {
printf (&%45s %10s\n&, &Context switch&, &COUNT&)
foreach ([task_prev, task_next] in csw_count- limit 20) {
printf(&%45s %10d\n&, fmt_task(task_prev, task_next), csw_count[task_prev, task_next])
printf(&%45s %10d\n&, &idle&, idle_count)
delete csw_count
delete idle_count
probe timer.s($1) {
print_cswtop ()
printf(&--------------------------------------------------------------\n&)
保存成cs.stp后,用stap cswmon.stp 5命令执行下。
8、发现是discover进程在反复和系统进程进行切换。从此消耗了大量资源。
9、从网上查了下减少切换进程的一些方法:
开发随后改了下:将线程数开大了一倍,控制在一个进程中。
重新打压了一下。发现上下文切换数降低到25万次左右。
此时的性能数据可以达到每秒260次左右,远远高于之前的80次。已经达到可以上线的需求。
但是由于页面中断书和上下文切换数还是很高,后续还是需要优化~
{测试窝原创文章,作者:曹承臻}
作者简介:曹承臻,06届大学本科毕业,数学专业,6年软件测试行业经验
该文章对我有帮助
270°|2697 人阅读|1
一篇不错的性能测试小记关于“磁盘IO与上下文切换数”的调优
后发表评论
秦天 的其他博文 更多
&testwo.com 测试窝,促进软件测试领域知识的传播。
测试窝常年法律顾问:
| 执业证号:80720多核cpu 为何进行硬盘读写的操作同时做别的操作也会慢?_百度知道
多核cpu 为何进行硬盘读写的操作同时做别的操作也会慢?
可是我觉得不是硬盘慢,cpu占用率也不高,但是比如我在解压缩一个大型游戏的时候,用搜狗输入法打字都很延迟。
我有更好的答案
也别把多核看得太神奇了,一个任务一般由一个核心处理,而在于硬盘,就说明。个人认为,个人电脑的瓶颈不在于几个核心:因为做别的操作也需要读写硬盘呗。比如你开个网页就要读写COOKI 用输入法也一样要读写盘硬文件,多核也要有支持多线程的操作系统和程序才可以发挥他的做用只要CPU占用率不高
采纳率:57%
那是硬盘慢,不是CPU的慢
应为硬盘在读写。所以比较慢,
硬盘在读写的时候,当然会卡了
安装的时候 比较卡
看一下进程,看资源占用情况。
为您推荐:
其他类似问题
您可能关注的内容
多核cpu的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。博客分类:
业务需求:将数据库表中的大数据以文本方式保存到本地磁盘,即通过线程写入文件。
业务实现:
主线程开启创建文件缓冲流,启动多条子线程,并将文件缓冲流提供给每个子线程
每个子线程调用DAO分页查询接口获取到的数据,组装拼接写入到文件缓冲流中
在这个简单的业务里面最需要注意的应该是每个子线程分页查询时的页码数,需要通过同步的方式来控制。
一、同步锁(synchronized)的方式
同步页码类:
* 同步对象,提供页码
public class SyncObj {
private int pageNo = 0;
public synchronized int getPageNo() {
pageNo ++;
return pageNo;
子线程类:
public class WriteFileThread implements Runnable {
protected final Log log = LogFactory.getLog(this.getClass());
private ItemMapper itemM
private SyncO
private BufferedWriter bufferwriter =
public WriteFileThread(String name, ItemMapper itemMapper, SyncObj obj, BufferedWriter bufferwriter){
this.name =
this.itemMapper = itemM
this.obj =
this.bufferwriter =
public void run() {
int pageNoCopy = 0;
List&Item& itemList =
StringBuilder sb = new StringBuilder();
Map&String, Object& param = new HashMap&String, Object&();
while(true){
pageNoCopy = obj.getPageNo();
log.info("线程["+name+"]获取到的当前页码为:"+pageNoCopy);
param.put("index", (pageNoCopy-1)*10000);
param.put("pageSize", 10000);//一万条读一次
itemList = itemMapper.queryPagination(param);
if(itemList == null || itemList.size() == 0){
log.info("线程["+name+"]在第"+pageNoCopy+"页退出了");
for(Item item : itemList){
sb.append(item.getItemNum()).append(item.getItemName()).append("\n");
bufferwriter.write(sb.toString());
sb.delete(0, sb.length());
bufferwriter.flush();//刷新流
} catch (IOException e) {
e.printStackTrace();
主线程(这里采用Http Request)代码:
@RequestMapping(value="/generate_file")
public void generateFile(){
File file = new File("D://"+System.currentTimeMillis()+".txt");
if(!file.exists()){
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
SyncObj obj = new SyncObj();
ExecutorService pool = Executors.newFixedThreadPool(20);
FileWriter filewriter =
BufferedWriter bufferwriter =
filewriter = new FileWriter(file, true);
bufferwriter = new BufferedWriter(filewriter);
for(int i=0; i&20; i++)
pool.execute(new WriteFileThread("线程"+(i+1), itemMapper, obj, bufferwriter));
Thread.sleep(1000*60);
} catch (Exception e) {
e.printStackTrace();
bufferwriter.close();
filewriter.close();
} catch (Exception e) {
e.printStackTrace();
二、原子类(AtomicXXX)及同步量计数器(CountDownLatch)的应用
同步页码类:无
这里使用了JDK自带的原子类,能够更高效的提供数据同步,所以同步页码类就不需要了。
子线程类:
public class WriteFileThread2 implements Runnable {
protected final Log log = LogFactory.getLog(this.getClass());
private ItemMapper itemM
private AtomicInteger pageNo;
private CountDownLatch countD
private BufferedWriter bufferwriter =
public WriteFileThread2(String name, ItemMapper itemMapper, AtomicInteger pageNo, CountDownLatch countDown, BufferedWriter bufferwriter){
this.name =
this.itemMapper = itemM
this.pageNo = pageNo;
this.bufferwriter =
this.countDown = countD
public void run() {
int pageNoCopy = 0;
List&Item& itemList =
StringBuilder sb = new StringBuilder();
Map&String, Object& param = new HashMap&String, Object&();
while(true){
pageNoCopy = pageNo.getAndIncrement();//原子量中获取页码,并且自增1
log.error("线程["+name+"]获取到的当前页码为:"+pageNoCopy);
param.put("index", (pageNoCopy-1)*10000);
param.put("pageSize", 10000);//每页获取一万条记录
itemList = itemMapper.queryPagination(param);
if(itemList == null || itemList.size() == 0){
log.info("线程["+name+"]在第"+pageNoCopy+"页退出了");
for(Item item : itemList){
sb.append(item.getItemNum()).append(item.getItemName()).append("\n");
bufferwriter.write(sb.toString());
sb.delete(0, sb.length());
bufferwriter.flush();//刷新流
countDown.countDown();//计数器自减1
} catch (IOException e) {
countDown.countDown();//计数器自减1
e.printStackTrace();
主线程代码:
@RequestMapping(value="/generate_file2")
public void generateFile2(){
final int threadNum = 20;//子线程数
File file = new File("D://"+System.currentTimeMillis()+".txt");
if(!file.exists()){
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
AtomicInteger pageNo = new AtomicInteger(1);//页码
CountDownLatch countDown = new CountDownLatch(threadNum);//计数器
ExecutorService pool = Executors.newFixedThreadPool(threadNum);//固定大小线程池
FileWriter filewriter =
BufferedWriter bufferwriter =
filewriter = new FileWriter(file, true);
bufferwriter = new BufferedWriter(filewriter);
for(int i=0; i&threadN i++)
pool.execute(new WriteFileThread2("线程"+(i+1), itemMapper, pageNo, countDown, bufferwriter));
countDown.await();//阻塞主线程
} catch (Exception e) {
e.printStackTrace();
bufferwriter.close();
filewriter.close();
} catch (Exception e) {
e.printStackTrace();
每个子线程必须公用主线程中的文件缓冲流;若子线程各自使用自己的文件缓冲流,在线程刷出缓冲流数据时出现了碰撞,会导致写入的数据内容窜了。
在我的程序中用了C3P0的数据源,需要注意设置最大可用连接数(maxPoolSize)及获取连接时等待超时时间(checkoutTimeout)以确保请求时不会出现超时异常。
因主线程感知不到子线程出现异常的情况,所以子线程出现异常时也需要减计数器,否则主线程会一直被阻塞。
按照正常的业务,当子线程中出现异常时,首先需要进行自我修复(例如:出现数据库连接异常时,可重新获取连接,重新进行查询操作);
若修复不成功(例如:数据本身存在问题),需要立即通知主线程,并且终止掉其他子线程。在这里可以简单实现成:在主线程中增加原子布尔值(AtomicBoolean)作为是否异常的状态标志位,每个子线程在循环时进行检查;若出现异常,计数器减一并跳出当前线程即可。
浏览: 227233 次
来自: 杭州
请问下@CacheEvict想删除多个缓存要怎么做,比如在添加 ...
zwllxs 写道楼主,如果一个方法中,有对象类型的参数,此时 ...
楼主,如果一个方法中,有对象类型的参数,此时如果 @Cache ...
使用 @Cacheable(value =&tes ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'多线程同时写不同的文件_百度知道
多线程同时写不同的文件
个线程同时、分别将数据写入不同的文件会发生冲突吗?比如1线程循环写入A。我听说IO访问是单&线程&的,因为只有一个磁头,而与此同时2线程循环写入B.TXT.TXT
我有更好的答案
不会,因为系统会调度所有线程,帮助各个线程排队写入(比如系统发现线程1正在操作磁盘,就让线程2等待一会),写程序时基本不用考虑。
这意味着多线程用GDI+批量保存图片也可以了?
采纳率:48%
设备调度是操作系统的功能,不用考虑。
为您推荐:
其他类似问题
多线程的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。

我要回帖

更多关于 redis多线程同时读写 的文章

 

随机推荐