技术开发 频道

C#源码共享:多线程测试SQL代码访问速度

        【IT168 评论】程序员在写Sql代码时,一般是一个人写完之后,一运行可快完事。其实这些是不够的,我们根本没有进行过多用户多线程的测试,如果是100个,一千个要同时访问,还会有这样的速度吗?

  我们自己反思一下是不是有这样的经历呢,我做的网站刚上传服务器,打开很快,调数据库1000条以内一秒用不了,感觉非常好,但过了不几天,就会感觉到网站很慢很慢,于是去检查测试

  其实这些可以提前做的,我下面来实现一个多线程测试网站访问速度的功能。

  效果

  说明:

  1.一次可以开N多个线程;

  2.可以设置要访问的地址;

  3.可以设置要循环访问的次数;

  相关技术点:

  1.C# Winform;

  2.httpHelper类;这是我之前自己写的一个类,大家可以参考一下(带证书,无视编码,设置代理等)

  3.多线程;

  4.线程之间的传参;

  5.委托与匿名委托的使用方法;

  实现步骤:

  1.新建一个CS项目,AutoFor,新建一个窗体为TextFor

  2.自己拉几个控件实现如下界面

  3.定义一个委托用来修改DataGridview的值,代码如下

//修改表格的委托
        
private delegate void UpDateDgvDelegate(string msg, int rowId, string columnName);

        
private UpDateDgvDelegate _upDateStateDelegate;
        
//构造器
        
public TextFor()
        {
            InitializeComponent();
            _upDateStateDelegate
= new UpDateDgvDelegate(UpDateDgv);
        }

        
/// <summary>
        
/// 修改表格的行数据
        
/// </summary>
        
/// <param name="msg">要修改为的数据</param>
        
/// <param name="rowId">行号</param>
        
/// <param name="columnName">列名</param>
        
private void UpDateDgv(string msg, int rowId, string columnName)
        {
            try
            {
                dgvTextFor.Rows[rowId].Cells[columnName].Value
= msg.ToString();
            }
            catch { }
        }

 

  4.在单击开始时先生成对应的线程表格式,就是界面上的DataGridview,大家看下代码

/// <summary>
        
/// 创建表格
        
/// </summary>
        
/// <param name="rows">生成多少行数</param>
        
private void CreateTable(int rows)
        {
            DataTable dt_Sale
= new DataTable();
            DataColumn dc
= null;
            
//线程ID
            dc
= new DataColumn();
            dc.ColumnName
= "线程ID";
            dc.DefaultValue
= "1";
            dc.DataType
= Type.GetType("System.String");
            dt_Sale.Columns.Add(dc);

            
//循环类型
            dc
= new DataColumn();
            dc.ColumnName
= "循环类型";
            dc.DefaultValue
= " ";
            dc.DataType
= Type.GetType("System.String");
            dt_Sale.Columns.Add(dc);

            
//当前循环次数
            dc
= new DataColumn();
            dc.ColumnName
= "当前循环次数";
            dc.DefaultValue
= " ";
            dc.DataType
= Type.GetType(" System.String");
            dt_Sale.Columns.Add(dc);

            
//开始时间
            dc
= new DataColumn();
            dc.ColumnName
= "开始时间";
            dc.DefaultValue
= " ";
            dc.DataType
= Type.GetType("System.String");
            dt_Sale.Columns.Add(dc);

            
//结束时间
            dc
= new DataColumn();
            dc.ColumnName
= "结束时间";
            dc.DefaultValue
= " ";
            dc.DataType
= Type.GetType("System.String");
            dt_Sale.Columns.Add(dc);

            
//总用时(毫秒)
            dc
= new DataColumn();
            dc.ColumnName
= "总用时(毫秒)";
            dc.DefaultValue
= " ";
            dc.DataType
= Type.GetType("System.String");
            dt_Sale.Columns.Add(dc);


            DataRow dr
= dt_Sale.NewRow();
            
for (int i = 1; i < rows; i++)
            {
                dr[
"线程ID"] = i.ToString();
                dr[
"循环类型"] = "For循环";
                dr[
"当前循环次数"] = "0";
                dr[
"开始时间"] = "00:00:00";
                dr[
"结束时间"] = "00:00:00";
                dr[
"总用时(毫秒)"] = "0";
                dt_Sale.Rows.Add(dr);
                dr
= dt_Sale.NewRow();
            }
            dgvTextFor.DataSource
= dt_Sale;
        }

 

  5.定义一个方法用来访问指定的网站就是我们的实际测试这块,

  一起来看下代码

/// <summary>
        
/// 执行数据
        
/// </summary>
        
/// <param name="dgvrowid"> 线程号行号</param>
        
/// <param name="number">循环总次数</param>
        
private void PingTask(int dgvrowid, int number)
        {
            
//获取开始时间
            DateTime st
= DateTime.Now;

            
//开始时间
            this.BeginInvoke(_upDateStateDelegate, st.ToString(
"hh-mm-ss"), dgvrowid, "开始时间");

            
for (int i = 0; i < number; i++)
            {
                try
                {
                    HttpHelps hh
= new HttpHelps();

                    
//自动访问百度,主要是延长时间
                    hh.GetHttpRequestStringByNUll_Get(
"www.baidu.com", null);

                    
//当前循环次数
                    this.BeginInvoke(_upDateStateDelegate, i.ToString(), dgvrowid,
"当前循环次数");

                    
//获取结束时间
                    DateTime et
= DateTime.Now;

                    
//结束时间
                    this.BeginInvoke(_upDateStateDelegate, et.ToString(
"hh-mm-ss"), dgvrowid, "结束时间");

                    
//总用时(毫秒)
                    this.BeginInvoke(_upDateStateDelegate, ExecDateDiff(st, et), dgvrowid,
"总用时(毫秒)");
                }
                catch { }
            }

        }

 

  我来解释下这句 //总用时(毫秒) this.BeginInvoke(_upDateStateDelegate, ExecDateDiff(st, et), dgvrowid, "总用时(毫秒)");

  第一个BeginInvoke方法,是用来异步执行委托的,系统自带方法。

  upDateStateDelegate是要执行的委托我们前面有定义

  ExecDateDiff计算时间差的方法自己写的如下代码

/// <summary>
        
/// 程序执行时间测试
        
/// </summary>
        
/// <param name="dateBegin">开始时间</param>
        
/// <param name="dateEnd">结束时间</param>
        
/// <returns>返回(秒)单位,比如: 0.00239秒</returns>
        
public static string ExecDateDiff(DateTime dateBegin, DateTime dateEnd)
        {
            TimeSpan ts1
= new TimeSpan(dateBegin.Ticks);
            TimeSpan ts2
= new TimeSpan(dateEnd.Ticks);
            TimeSpan ts3
= ts1.Subtract(ts2).Duration();
            return ts3.TotalMilliseconds.ToString();
        }

 

  注意,大家一定要记着这里的类型要和委托的类型是一样的,否则为出错,而且它不会自动转化,如果你定义的是String,传的是int是不可以的, 要手动的去转,这点请大家注意一下。

  dgvrowid启动线程所在DataGridview行,一行是一个线程的变化情况

  "总用时(毫秒)" 列名,这里是为了方便 大家看,使用的汉语大家见谅。

  6.启动线程,我们只要执行一个For就可以循环启动了,大家一起来看看方法吧

private void button3_Click(object sender, EventArgs e)
        {
            
int count = Convert.ToInt32(txtCount.Text.Trim());
            
int number = Convert.ToInt32(txtNumber.Text.Trim());
            CreateTable(count
+ 1);
            
//开启number个线程
            
for (int i = 0; i < count; i++)
            {
                Thread pingTask
= new Thread(new ThreadStart(delegate
               {
                   PingTask(i, number);
               }));
                pingTask.Start();
                Thread.Sleep(
100);
            }
        }

 

  我们都知道线程是不能直接传参数的,只能传Object,但使用匿名委托就可以解决 这个问题,方法如上面,大家看不明白的可以留言给我。

  Thread.Sleep(100); 是为了让线程正常启动做了一个时间间隔。

  大家可以根据自己的情况调整

  其实这个例子不但可以实现这样测试,大家还可以用来访问数据库,开上几千个线程,看看你的Sql代码访问速度有多快。个人感觉很不错的一种压力测试方法。

     源码下载:http://download.csdn.net/detail/sufei1013/4017086

0
相关文章