• C#多线程|匿名委托传参数|测试您的网站能承受的压力|附源代码


    源代码下载:http://www.sufeinet.com/thread-13-1-1.html

    引言


        我们一直在做网站,但在我河南这块,对测试工作,特别是压力测试一般都不怎么在意,都是自己访问一下速度不错就行了,再就是数据库访问速度测试也是同样情况

    程序员在写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代码访问速度有多快。

    个人感觉很不错的一种压力测试方法

    希望大家多提提建议哦

        

       

    本人的博客不再维护从2013年就不再维护了 需要我帮助的朋友请到我的个人论坛 http://www.sufeinet.com 进行讨论,感谢大家对我的支持!
  • 相关阅读:
    1.打开windows中功能的快捷方式
    16-SQLServer强制走索引
    15-资源等待类型sys.dm_os_wait_stats
    14-SQLServer索引碎片
    13-修复数据库,表,索引
    12-SSMS图形化工具中不允许保存修改的解决办法
    11-常用SQL总结
    10-SQLServer中统计信息的使用
    Java连接mysql数据库
    递归方式的对变量中的特殊字符进行转义/去除转义
  • 原文地址:https://www.cnblogs.com/sufei/p/2320430.html
Copyright © 2020-2023  润新知