zoukankan      html  css  js  c++  java
  • 测试 ClownFish、CYQ、Entity Framework、Moon、MySoft、NHibernate、PDF、XCode数据访问组件性能

    下期预告:

    由于很多园友反馈,有的组件不应该缺席、测试复杂度不够、测试还缺乏一定的公平。

    因此考虑在下一个版本中,确保在更加公平的前提下进行更高复杂度的测试 。

    同时将分为2组测试,纯SQL组件及纯ORM组件, 如果纯SQL组件不足,就只进行纯ORM组件的测试。

    待加入测试组件有Dapper、PetaPoco/NPoco、Elinq、FluentData ,有更好的建议,请留言。

    --------------------------------------------------------------

    “啊!你在用ORM?会不会性能很差啊?”

    用数字来说话,打破模糊的、传言的印象。

    标题提到的组件“增删改查”都实现了测试代码,所以除了测试外,也可以把此项目作为各个组件的入门参考demo。

    源码下载:https://github.com/alifellod/DbAccessLibTest/archive/master.zip

    git地址:https://github.com/alifellod/DbAccessLibTest  欢迎园友贡献改进代码。

    项目使用的是.Net Framework 4.0可以使用2010或2012打开。

    默认测试数据库使用SqlServer

    测试前,请先创建数据表Test(使用名为Test的数据库,如果不用这个数据库,请更改数据库连接字符串)

    CREATE TABLE [dbo].[Test]
    (
        [RowId] [int] IDENTITY(1,1NOT NULL,
        [Guid] [varchar](50primary key NOT NULL,
        [Content] [nvarchar](500NULL,
        [CreateDate] [datetime] NULL default getdate(),
        [EditDate] [datetime] NULL
    )

    测试前清表:truncatetable Test
    默认连接字符串是:Data Source=.;Initial Catalog=Test;Integrated Security=True

    此程度测试代码使用了接口规范,并没有为了省事耦合在程序里,因此编写修改测试代码非常简单,所以也希望各位园友自己写上一段测试测试。
    由于这些组件基本都是第一次使用,所以可能导致部分组件测试代码编写并不合理,敬请指点。
    注意:各组件的测试均采用一样的测试思路,也即ORM对ORM,SQL对SQL,循环也是一样的循环。
    不必拘泥于15和23的区别,而是要区别10和100的区别,也就是在一个数量级别之间比较。
    线程我分别写了Task、ThreadPool和Thread的执行方式,根据自己的喜欢选择。

    Task可以很出色的取消创建的线程,ThreadPool测试会较为稳定,Thread很容易导致SQL连接池爆破。
    测试之前,可先预热一下——各个组件进行一定数量查询。

    先看两张测试图。

    分别是ClownFish和EF的测试图,X轴是线程名称,Y轴是耗时。

     

     

    特别说明: CYQ的数据是使用更新前的组件,在昨晚测试整理的。今天收到秋天园友的反馈,已经在git提交了更新,测试的数据也回归正常。

    因此,数据也调整过来。(2013-07-27 13:53)

    关于XCode的测试数据,请参看大石头的说明。大石头建议在大数据的访问时使用此组件,并开启缓存。

    同时不再接受新的组件更新,除非是在新的测试版本中,以避免针对性的更新。

    数据格式:平均值-最高值-最低值
    测试顺序:增、改、删
    100“线程” 查询10次 增删改
     

     

    ClownFish

    Moon

    PDF

    23-96-2

    21-76-6

    8-25-4

    16-49-2

    15-37-5

    4-18-2

    46-116-3

    23-56-3

    7-33-3

     

    CYQOrm

    EFOrm

    MoonOrm

    MySoftOrm

    NHibernateOrm

    PDFOrm

    XCodeOrm

     24-79-5

    23-71-8

    10-64-3

    46-102-24

    21-47-7

    12-31-4

    15-60-9

     11-61-4

    61-137-17

    10-29-3

    41-267-15

    41-103-9

    20-54-3

    340-623-173

    29-182-18

    37-113-15

    5-15-2

    110-195-52

    37-128-7

    17-50-3

    364-476-246


    1000“线程” 查询10次增删改

     

    ClownFish

    Moon

    PDF

    9-276-2

    13-49-2

    7-44-3

    22-125-2

    7-43-3

    9-41-3

    20-299-2

    10-123-3

    8-66-2

     

    CYQOrm

    EFOrm

    MoonOrm

    MySoftOrm

    NHibernateOrm

    PDFOrm

    XCodeOrm

     79-961-3

    29-306-9

    6-52-3

    50-386-11

    12-259-4

    10-48-3

    14-231-8

     29-471-4

    43-321-11

    14-95-2

    78-386-13

    45-237-7

    22-90-4

    362-729-177

     30-438-3

    59-334-12

    27-215-14

    106-647-18

    42-294-4

    17-128-3

    410-755-199

    查询测试,数据行100W
    100“线程” 查询返回Top 100
    使用没有索引的列RowId排序

     

    ClownFish

    Moon

    PDF

    2-19-1

    1-9-0

    1-47-0

    查询采用的根据组件提供的分页或者Top查询功能。(moon及xcode使用的是分页查询)
    使用没有索引的列RowId排序

     

    CYQOrm

    EFOrm

    MoonOrm

    MySoftOrm

    NHibernateOrm

    PDFOrm

    XCodeOrm

    1339-2220-281

    1452-3668-735

    5230-8032-3241

    1287-1670-240

    3372-6264-954

    2629-3825-836

    1696-5363-716

    使用有索引的列Guid排序

     

    CYQOrm

    EFOrm

    MoonOrm

    MySoftOrm

    NHibernateOrm

    PDFOrm

    XCodeOrm

    16-32-13

    5-8-3

    5967-14644-1639

    2-5-1

    7-127-2

    1-17-0

    1-9-0

    经过测试,发现线程越多,越容易出现问题“超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。”导致访问很不稳定。
    一个好的数据访问层应该是可以优雅的接受并处理大并发的访问,而不应该仅仅只盯住表面上的测试数据(除非有数量级上的差距)。
    整个程序框架怎么才设计出色,更加优雅的面对请求,才是应该花更多心思去考虑的。
    从上面也可以看到,ORM性能其实并没有一般人想象的那么糟糕。

    最后看看程序的代码是怎么样的。

    项目目录

    测试代码接口

    public interface ITest
    {
        bool Insert();
        bool Update(string guid, string content);
        DataTable Select(int count);
        List<string> GetGuidList(int count);
        bool Delete(string guid);
    }
    View Code

    ClownFish-SQL测试代码

    public class ClownFishTest : DbContextHolderBase, ITest
    {
        static ClownFishTest()
        {
            DbContext.RegisterDbConnectionInfo("sqlserver""System.Data.SqlClient""@", Control.ConnectionStrings);
        }
        public void TruncateTable()
        {
            DbHelper.ExecuteNonQuery(SqlString.TruncateTable, null, DbContext, CommandKind.SqlTextNoParams);
        }
        public bool Insert()
        {
            var parameter = new { Guid = Guid.NewGuid(), Content = string.Empty };
            return (DbHelper.ExecuteNonQuery(SqlString.Insert, parameter, DbContext, CommandKind.SqlTextWithParams) > 0);
        }
        public bool Update(string guid, string content)
        {
            var parameter = new { Guid = guid, Content = content };
            return (DbHelper.ExecuteNonQuery(SqlString.Update, parameter, DbContext, CommandKind.SqlTextWithParams) > 0);
        }
        public DataTable Select(int count)
        {
            return DbHelper.FillDataTable(string.Format(SqlString.Select, count), null, DbContext, CommandKind.SqlTextNoParams);
        }
        public List<string> GetGuidList(int count)
        {
            List<string> result = new List<string>();
            DataTable dtb = Select(count);
            if (dtb == null || dtb.Rows.Count == 0)
                return result;
            result.AddRange(from DataRow row in dtb.Rows select row["Guid"].ToString());
            return result;
        }
        public bool Delete(string guid)
        {
            var parameter = new { Guid = guid };
            return (DbHelper.ExecuteNonQuery(SqlString.Delete, parameter, DbContext, CommandKind.SqlTextWithParams) > 0);
        }
    }
    View Code
    Moon-SQL测试代码
    public class MoonTest : ITest
    {
        private readonly DB _dbHelper = DBFactory.DefaultDB;
        public bool Insert()
        {
            return (_dbHelper.ExecuteOneSql(string.Format(SqlString.InsertFormat, Guid.NewGuid(), string.Empty)) > 0);
        }
        public bool Update(string guid, string content)
        {
            return (_dbHelper.ExecuteOneSql(string.Format(SqlString.UpdateFormat, guid, content)) > 0);
        }
        public DataTable Select(int count)
        {
            return _dbHelper.GetDataTable(string.Format(SqlString.Select, count));
        }
        public List<string> GetGuidList(int count)
        {
            List<string> result = new List<string>();
            DataTable dtb = Select(count);
            if (dtb == null || dtb.Rows.Count == 0)
                return result;
            result.AddRange(from DataRow row in dtb.Rows select row["Guid"].ToString());
            return result;
        }
        public bool Delete(string guid)
        {
            return (_dbHelper.ExecuteOneSql(string.Format( SqlString.DeleteFormat,guid)) > 0);
        }
    }
    View Code

    PDF-SQL测试代码

    public class PdfTest : ITest
    {
        private readonly AdoHelper _dbHelper = MyDB.GetDBHelperByConnectionName("pdf");
        public bool Insert()
        {
            IDataParameter[] parameters =
            {
                new SqlParameter("@Guid",SqlDbType.VarChar,50){Value=Guid.NewGuid().ToString()},
                new SqlParameter("@Content",SqlDbType.NVarChar,500){Value=string.Empty}
            };
            return (_dbHelper.ExecuteNonQuery(SqlString.Insert, CommandType.Text, parameters) > 0);
        }
        public bool Update(string guid, string content)
        {
            IDataParameter[] parameters =
            {
                new SqlParameter("@Guid",SqlDbType.VarChar,50){Value=guid},
                new SqlParameter("@Content",SqlDbType.NVarChar,500){Value=content}
            };
            return (_dbHelper.ExecuteNonQuery(SqlString.Update, CommandType.Text, parameters) > 0);
        }
        public DataTable Select(int count)
        {
            return _dbHelper.ExecuteDataSet(string.Format(SqlString.Select, count)).Tables[0];
        }
        public List<string> GetGuidList(int count)
        {
            List<string> result = new List<string>();
            DataTable dtb = Select(count);
            if (dtb == null || dtb.Rows.Count == 0)
                return result;
            result.AddRange(from DataRow row in dtb.Rows select row["Guid"].ToString());
            return result;
        }
        public bool Delete(string guid)
        {
            IDataParameter[] parameters =
            {
                new SqlParameter("@Guid",SqlDbType.VarChar,50){Value=guid}
            };
            return (_dbHelper.ExecuteNonQuery(SqlString.Delete, CommandType.Text, parameters) > 0);
        }
    }
    View Code

    CYQ-ORM测试代码

    public class CyqOrmTest : ITest
    {
        public bool Insert()
        {
            bool result;
            using (MAction actiont = new MAction(TableNames.Test))
            {
                actiont.Set("Guid", Guid.NewGuid());
                result = actiont.Insert(InsertOp.None);
            }
            return result;
        }
        public bool Update(string guid, string content)
        {
            bool result;
            using (MAction actiont = new MAction(TableNames.Test))
            {
                actiont.Set("Content", content);
                result = actiont.Update("Guid='" + guid + "'");
            }
            return result;
        }
        public DataTable Select(int count)
        {
            DataTable result;
            using (MAction actiont = new MAction(TableNames.Test))
            {
                result = actiont.Select(count, "order by Guid").ToDataTable();
                //actiont.Select(count, "order by RowId");
            }
            return result;
        }
        public List<string> GetGuidList(int count)
        {
            List<string> result = new List<string>();
            DataTable dtb = Select(count);
            if (dtb == null || dtb.Rows.Count == 0)
                return result;
            result.AddRange(from DataRow row in dtb.Rows select row["Guid"].ToString());
            return result;
        }
        public bool Delete(string guid)
        {
            bool result;
            using (MAction actiont = new MAction(TableNames.Test))
            {
                result = actiont.Delete("Guid='" + guid + "'");
            }
            return result;
        }
    }
    View Code

    EF-ORM测试代码

    public class EFOrmTest : ITest
    {
        private readonly EFDbContext _dbContext;
        //private static readonly EFDbContext _dbContext = new EFDbContext("Conn");
        public EFOrmTest()
        {
            _dbContext = new EFDbContext("Conn");
        }
        public bool Insert()
        {
            DbSet model = _dbContext.Set();
            model.Add(new TestModel { Guid = Guid.NewGuid().ToString(), EditDate = DateTime.Now });
            _dbContext.SaveChanges();
            return true;
        }

        public bool Update(string guid, string content)
        {
            var model = _dbContext.Set().Find(guid);
            model.Content = content;
            _dbContext.Entry(model).State = EntityState.Modified;
            _dbContext.SaveChanges();
            return true;
        }

        public DataTable Select(int count)
        {
            GetModelList(count);
            return null;
        }

        public IList GetModelList(int count)
        {
            DbSet model = _dbContext.Set();
            return model.OrderBy(o => o.Guid).Take(count).ToList();
        }

        public List<string> GetGuidList(int count)
        {
            List<string> result = new List<string>();
            var list = GetModelList(count);
            if (list == null || list.Count == 0)
                return result;
            result.AddRange(list.Select(o => o.Guid));
            return result;
        }

        public bool Delete(string guid)
        {
            var model = _dbContext.Set().Find(guid);
            _dbContext.Entry(model).State = EntityState.Deleted;
            _dbContext.SaveChanges();
            return true;
        }
    }
    View Code

    Moon-ORM测试代码

    public class MoonOrmTest : ITest
    {
        public static void Init() { }
        public bool Insert()
        {
            return DBFactory.Add(new MoonTestModel { Guid = Guid.NewGuid().ToString() }) != DBNull.Value;
        }
        public bool Update(string guid, string content)
        {
            var model = new MoonTestModel() { Content = content };
            model.SetOnlyMark(TestTable.Guid.Equal(guid));
            DBFactory.Update(model);
            return true;
        }
        public DataTable Select(int count)
        {
            GetModelList(count);
            return null;
        }
        public IList GetModelList(int count)
        {
            //没有找到更好的查询方式
            return DBFactory.DefaultDB.GetPagedListDesc(1, count, TestTable.Guid, TestTable.Guid.NotEqual("''"));
        }
        public List<string> GetGuidList(int count)
        {
            List<string> result = new List<string>();
            var list = GetModelList(count);
            if (list == null || list.Count == 0)
                return result;
            result.AddRange(list.Select(moonTestModel => moonTestModel.Guid));
            return result;
        }
        public bool Delete(string guid)
        {
            return DBFactory.DeleteWhen(TestTable.Guid.Equal(guid)) > 0;
        }
    }
    View Code

    MySoft-ORM测试代码

    public class MySoftOrmTest : ITest
    {
        private static readonly DbSession DBSession = new DbSession(new MySoft.Data.SqlServer9.SqlServer9Provider(System.Configuration.ConfigurationManager.ConnectionStrings["Conn"].ConnectionString));

        public bool Insert()
        {
            return DBSession.Insert(new[] { MySoftTestModel._.Guid }, new object[] { Guid.NewGuid().ToString() }) > 0;
        }

        public bool Update(string guid, string content)
        {
            return DBSession.Update(new[] { MySoftTestModel._.Content, MySoftTestModel._.EditDate }, new object[] { content, DateTime.Now }, MySoftTestModel._.Guid == guid) > 0;
        }

        public DataTable Select(int count)
        {
            GetModelList(count);
            return null;
        }
        public IList GetModelList(int count)
        {
            return DBSession.From().OrderBy(MySoftTestModel._.Guid.Asc).GetTop(count).ToList();
        }

        public List<string> GetGuidList(int count)
        {
            List<string> result = new List<string>();
            var list = GetModelList(count);
            if (list == null || list.Count == 0)
                return result;
            result.AddRange(list.Select(o => o.Guid));
            return result;
        }

        public bool Delete(string guid)
        {
            return DBSession.Delete(MySoftTestModel._.Guid == guid) > 0;
        }
    }
    View Code

    NHibernate-ORM测试代码

    public class NHibernateOrmTest : ITest
    {
        private static readonly ISessionFactory SessionFactory = CreateSessionFactory();
        static NHibernateOrmTest()
        {
        }
        private static ISessionFactory CreateSessionFactory()
        {
            ISessionFactory sessionFactory;
            try
            {
                sessionFactory = Fluently.Configure()
                                .Database(FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2008
                                .ConnectionString(s => s.Server(".").Database("Test")
                                    .TrustedConnection()))
                                .Mappings(m =>m.FluentMappings.Add())
                                .BuildSessionFactory();
            }
            catch (Exception ex)
            {
                throw;
            }
            return sessionFactory;
        }
        public bool Insert()
        {
            using (var session = SessionFactory.OpenSession())
            {
                var model = new TestModel { Guid = Guid.NewGuid().ToString() };
                session.Save(model);
                session.Flush();
            }
            return true;
        }

        public bool Update(string guid, string content)
        {
            using (var session = SessionFactory.OpenSession())
            {
                var model = new TestModel { Guid = guid, Content = content, EditDate = DateTime.Now };
                session.Update(model);
                session.Flush();
            }
            return true;
        }

        public DataTable Select(int count)
        {
            GetModelList(count);
            return null;
        }
        public IList GetModelList(int count)
        {
            IList result;
            using (var session = SessionFactory.OpenSession())
            {
                result = session.QueryOver().OrderBy(o=>o.Guid).Asc.Take(count).List();
            }
            return result;
        }
        public List<string> GetGuidList(int count)
        {
            List<string> result = new List<string>();
            var list = GetModelList(count);
            if (list == null || list.Count == 0)
                return result;
            result.AddRange(list.Select(o => o.Guid));
            return result;
        }

        public bool Delete(string guid)
        {
            using (var session = SessionFactory.OpenSession())
            {
                var model = new TestModel { Guid = guid};
                session.Delete(model);
                session.Flush();
            }
            return true;
        }
    }
    View Code
    PDF-ORM测试代码
    public class PdfOrmTest : ITest
    {
        public bool Insert()
        {
            PdfTestModel model = new PdfTestModel
            {
                Guid = Guid.NewGuid().ToString(),
                EditDate = DateTime.Now
            };
            return EntityQuery<PdfTestModel>.Instance.Insert(model) > 0;
        }
        public bool Update(string guid, string content)
        {
            PdfTestModel model = new PdfTestModel
            {
                Guid = guid,
                Content = content,
                EditDate = DateTime.Now
            };
            return EntityQuery<PdfTestModel>.Instance.Update(model) > 0;
        }
        public DataTable Select(int count)
        {
            GetModelList(count);
            return null;
        }
        public List<PdfTestModel> GetModelList(int count)
        {
            PdfTestModel model = new PdfTestModel();
            OQL q = OQL.From(model).Limit(count).Select().OrderBy(model.Guid, "ASC").END;
            return EntityQuery<PdfTestModel>.QueryList(q);
        }
        public List<string> GetGuidList(int count)
        {
            List<string> result = new List<string>();
            var list = GetModelList(count);
            if (list == null || list.Count == 0)
                return result;
            result.AddRange(list.Select(o => o.Guid));
            return result;
        }
        public bool Delete(string guid)
        {
            PdfTestModel model = new PdfTestModel { Guid = guid };
            return EntityQuery<PdfTestModel>.Instance.Delete(model) > 0;
        }
    }
    View Code

    XCode-ORM测试代码

    public class XCodeOrmTest : ITest
    {
        static XCodeOrmTest()
        {
            XCode.DataAccessLayer.DAL.ShowSQL = false;
            //XCode.DataAccessLayer.DAL.SQLPath = AppDomain.CurrentDomain.BaseDirectory;
        }
        public bool Insert()
        {
            var model = new XCodeTestModel();
            model.Guid = Guid.NewGuid().ToString();
            return model.Insert() > 0;

        }
        public bool Update(string guid, string content)
        {
            var model = XCodeTestModel.FindByGuid(guid);
            model.Content = content;
            model.EditDate = DateTime.Now;
            return model.Update() > 0;
        }
        public DataTable Select(int count)
        {
            GetModelList(count);
            return null;
        }
        public List GetModelList(int count)
        {
            return XCodeTestModel.Search(string.Empty, "Guid ASC"0, count);
        }
        public List<string> GetGuidList(int count)
        {
            List<string> result = new List<string>();
            var list = GetModelList(count);
            if (list == null || list.Count == 0)
                return result;
            result.AddRange(list.Select(o => o.Guid));
            return result;
        }
        public bool Delete(string guid)
        {
            //return XCodeTestModel.Delete(new[] { "Guid" }, new object[] { guid }) > 0;
            return XCodeTestModel.FindByGuid(guid).Delete() > 0;
        }
    }
    View Code

    测试耗时监控

    /// 

    /// 执行指定查询的测试,并记录测试数据
    /// 

    /// 线程序号
    /// 执行的查询
    /// 执行测试的组件实体
    private object TestWork(object index, Actionint> execute, ITest instance)
    {
        Stopwatch sw = new Stopwatch();
        string threadName = string.Format("{0:D3}", index);
        if (_showThreadWorkStatus)
            UpdateMessage(string.Format("线程{0}开始时间:{1}", threadName, DateTime.Now));
        sw.Start();
        try
        {execute(instance, (int) index);}
        catch (Exception ex)
        {UpdateMessage(string.Format("*线程{0} 执行错误,信息:{1}", threadName, ex.Message));}
        sw.Stop();
        if (_showThreadWorkStatus)
            UpdateMessage(string.Format("*线程{0}  *总耗时:{1}   *当前时间:{2}", threadName, sw.ElapsedMilliseconds, DateTime.Now));
        _waitWrite.WaitOne();
        _waitWrite.Reset();
        _workThreadCount--;
        _totalElapsed += sw.ElapsedMilliseconds;
        _workerInfo.Add(new Worker { Name = threadName, TotalElapsed = sw.ElapsedMilliseconds });

        if (_workThreadCount == 0)
        {
            UpdateMessage(string.Format("全部线程总耗时:{0} *开始时间:{1}  *结束时间:{2}", _totalElapsed, _beginTime, DateTime.Now));
            UpdateChart();
            EnableExecuteControl();
        }
        Application.DoEvents();
        UpdateThreadCountBack();
        _waitWrite.Set();
        return 0;
    }
    View Code

    测试完整逻辑代码 ,300多行,慎点。

    public partial class FrmDbAccessTest : Form
    {
        private string _executeType = "Insert";//测试查询类型
        private string _testLibClassPath = "DbAccessLibTest.Test.ClownFishTest";//测试组件类路径
        private long _totalElapsed;//总耗时
        private int _workThreadCount;//工作线程数
        private int _threadCountCreated, _threadCountBack;
        private int _executeCount;//执行查询次数(返回行数)
        private bool _showThreadWorkStatus;
        private Dictionary<int, List<string>> _guidList;//执行删除和修改时,预先取回的主键guid集合,按照每个线程序号分组分配
        private List _workerInfo;//测试工作线程信息,主要用于图表数据显示
        private ITest _testInstance;//用于准备执行删除、修改的guid集合
        private DateTime _beginTime;//测试开始的时间
        private readonly AutoResetEvent _waitWrite = new AutoResetEvent(true);//编辑总耗时等全局信息的信号灯
        private CancellationTokenSource _taskCancelToken;
        private readonly Assembly _self = Assembly.Load("数据访问组件测试");
        public FrmDbAccessTest()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            _workerInfo = new List();
            chartMain.Series[0].XValueMember = "Name";
            chartMain.Series[0].YValueMembers = "TotalElapsed";
            chartMain.DataSource = _workerInfo;
        }
        /// 

        
    /// 执行测试
        
    /// 

        private void btnExecute_Click(object sender, EventArgs e)
        {
            //初始化数据
            _workThreadCount = (int)nuWorkThreadCount.Value;
            _executeCount = (int)nuExecuteCount.Value;
            _totalElapsed = 0;
            _workerInfo = new List();
            _testLibClassPath = "DbAccessLibTest.Test." + cmbTestLib.Text;
            _testInstance = (ITest)_self.CreateInstance(_testLibClassPath);
            _beginTime = DateTime.Now;
            UpdateMessage(string.Format("测试开始时间:{0}", DateTime.Now));
            UpdateMessage(string.Format("  启动线程数:{0}", _workThreadCount));
            UpdateMessage(string.Format("  执行操作数:{0}", _executeCount));
            btnExecute.Enabled = false;
            nuThreadCountBack.Value = _threadCountBack = 0;
            nuThreadCountCreated.Value = _threadCountCreated = 0;
            _showThreadWorkStatus = ckbShowThreadStatus.Checked;
            ckbShowThreadStatus.Enabled = false;

            new Thread(TestMain).Start();
        }

        private void TestMain()
        {
            try
            {
                UpdateMessage(string.Format("数据准备开始:{0}", DateTime.Now));
                Actionint> testExecute = GetExecuteUse();
                UpdateMessage(string.Format("数据准备结束:{0}", DateTime.Now));
                int createCount = _workThreadCount;
                UpdateMessage(string.Format("开始创建线程:{0}", DateTime.Now));
                _taskCancelToken = new CancellationTokenSource();
                for (int index = 0; index < createCount; index++)
                {
                    if (IsDisposed)
                        return;//防止重启程序时,仍然不断创建线程
                    if (rdbThreadPool.Checked)
                        UseThreadPool(index, testExecute);
                    else if (rdbThread.Checked)
                        UseThread(index, testExecute);
                    else
                    {
                        if (!UseTask(index, testExecute))
                            return;//如果已经重启程序,则跳出
                    }
                    Thread.Sleep(50);
                    UpdateThreadCountCreated();
                }
                UpdateMessage(string.Format("创建线程完毕:{0}", DateTime.Now));
            }
            catch (Exception ex)
            {
                UpdateMessage(ex.Message);
            }
        }
        private void UseThreadPool(int index, Actionint> testExecute)
        {
            ThreadPool.QueueUserWorkItem(
                                        threadIndex =>
                                        TestWork(threadIndex, testExecute
                                        , (ITest)_self.CreateInstance(_testLibClassPath)), index);
        }
        private void UseThread(int index, Actionint> testExecute)
        {
            new Thread(
                    threadIndex =>
                    TestWork(threadIndex, testExecute
                    , (ITest)_self.CreateInstance(_testLibClassPath)))
                    .Start(index);
        }
        private bool UseTask(int index, Actionint> testExecute)
        {
            var task = new Task<object>
                (
                    threadIndex => TestWork(threadIndex, testExecute, (ITest)_self.CreateInstance(_testLibClassPath))
                    , index
                    , _taskCancelToken.Token
                );
            if (_taskCancelToken.IsCancellationRequested)
                return false;
            task.Start();
            return true;
        }
        /// 

        
    /// 执行指定查询的测试,并记录测试数据
        
    /// 

        
    /// 线程序号
        
    /// 执行的查询
        
    /// 执行测试的组件实体
        private object TestWork(object index, Actionint> execute, ITest instance)
        {
            Stopwatch sw = new Stopwatch();
            string threadName = string.Format("{0:D3}", index);
            if (_showThreadWorkStatus)
                UpdateMessage(string.Format("线程{0}开始时间:{1}", threadName, DateTime.Now));
            sw.Start();
            try
            {execute(instance, (int) index);}
            catch (Exception ex)
            {UpdateMessage(string.Format("*线程{0} 执行错误,信息:{1}", threadName, ex.Message));}
            sw.Stop();
            if (_showThreadWorkStatus)
                UpdateMessage(string.Format("*线程{0}  *总耗时:{1}   *当前时间:{2}", threadName, sw.ElapsedMilliseconds, DateTime.Now));
            _waitWrite.WaitOne();
            _waitWrite.Reset();
            _workThreadCount--;
            _totalElapsed += sw.ElapsedMilliseconds;
            _workerInfo.Add(new Worker { Name = threadName, TotalElapsed = sw.ElapsedMilliseconds });

            if (_workThreadCount == 0)
            {
                UpdateMessage(string.Format("全部线程总耗时:{0} *开始时间:{1}  *结束时间:{2}", _totalElapsed, _beginTime, DateTime.Now));
                UpdateChart();
                EnableExecuteControl();
            }
            Application.DoEvents();
            UpdateThreadCountBack();
            _waitWrite.Set();
            return 0;
        }
        #region 执行查询

        private void ExecuteInsert(ITest instance, int threadIndex)
        {
            for (int i = 0; i < _executeCount; i++)
                instance.Insert();
        }

        private void ExecuteUpdate(ITest instance, int threadIndex)
        {
            foreach (string guid in _guidList[threadIndex])
                instance.Update(guid, string.Format("测试修改 **线程:{0}**组件:{1}**时间:{2}", threadIndex, instance.GetType(), DateTime.Now));
        }

        private void ExecuteDelete(ITest instance, int threadIndex)
        {
            foreach (string guid in _guidList[threadIndex])
                instance.Delete(guid);
        }

        private void ExecuteSelect(ITest instance, int threadIndex)
        {
            instance.Select(_executeCount);
        }

        #endregion

        /// 

        
    /// 获取测试的操作,如果是删除和更新,则先准备数据
        
    /// 

        
    /// 
        private Actionint> GetExecuteUse()
        {
            switch (_executeType)
            {
                case "Insert":
                    return ExecuteInsert;
                case "Delete":
                    AssignGuid(); return ExecuteDelete;
                case "Update":
                    AssignGuid(); return ExecuteUpdate;
                case "Select":
                    return ExecuteSelect;
            }
            throw new Exception("程序异常:GetExecute");
        }
        /// 

        
    /// 获取删除或者更新需要的guid集合,并分配给各个线程
        
    /// 

        private void AssignGuid()
        {
            var list = _testInstance.GetGuidList(_workThreadCount * _executeCount);
            _guidList = new Dictionary<int, List<string>>(_workThreadCount);
            for (int i = 0; i < _workThreadCount; i++)
                _guidList.Add(i, new List<string>());
            for (int i = 0; i < list.Count; i++)
            {
                int index = i % _workThreadCount;
                _guidList[index].Add(list[i]);
            }
        }
        /// 

        
    /// 更新图表
        
    /// 

        private void UpdateChart()
        {
            if (IsDisposed)
                return;
            if (InvokeRequired)
                BeginInvoke(new MethodInvoker(UpdateChart));
            else
            {
                if (_workerInfo.Count > 10)
                    chartMain.Series[0].Label = string.Empty;
                _workerInfo.Sort();
                chartMain.DataSource = _workerInfo;
                chartMain.ResetAutoValues();
            }
        }
        /// 

        
    /// 更新信息
        
    /// 

        
    /// 
        private void UpdateMessage(string msg)
        {
            if (IsDisposed)
            {
                return;
            }
            if (InvokeRequired)
                BeginInvoke(new MethodInvoker(() => UpdateMessage(msg)));
            else
            {
                rtxtMessage.AppendText(msg + " ");
                rtxtMessage.Select(rtxtMessage.Text.Length - 11);
                rtxtMessage.ScrollToCaret();
            }
        }
        /// 

        
    /// 更新已创建线程数
        
    /// 

        private void UpdateThreadCountCreated()
        {
            if (IsDisposed)
                return;
            if (InvokeRequired)
                BeginInvoke(new MethodInvoker(UpdateThreadCountCreated));
            else
                nuThreadCountCreated.Value = _threadCountCreated = (int)nuThreadCountCreated.Value + 1;
        }
        /// 

        
    /// 更新返回线程数
        
    /// 

        private void UpdateThreadCountBack()
        {
            if (IsDisposed)
                return;
            if (InvokeRequired)
                BeginInvoke(new MethodInvoker(UpdateThreadCountBack));
            else
                nuThreadCountBack.Value = _threadCountBack = (int)nuThreadCountBack.Value + 1;
        }

        /// 

        
    /// 启用执行按钮
        
    /// 

        private void EnableExecuteControl()
        {
            if (IsDisposed)
                return;
            Invoke(new MethodInvoker(() =>
            {
                btnExecute.Enabled = true;
                ckbShowThreadStatus.Enabled = true;
            }));
        }
        private void rdbExecute_CheckedChanged(object sender, EventArgs e)
        {
            RadioButton rdb = sender as RadioButton;
            if (rdb == null)
                throw new Exception("程序异常:rdbExecute_CheckedChanged");
            if (rdb.Checked)
                _executeType = rdb.Text;
        }

        private void btnAnalysis_Click(object sender, EventArgs e)
        {
            //暂时没有实现
        }
        private void btnTruncateTable_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("确定要清空整个表吗""提示", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) == DialogResult.Yes)
            {
                btnTruncateTable.Enabled = false;
                new ClownFishTest().TruncateTable();
                UpdateMessage("表已清空 - " + DateTime.Now);
                btnTruncateTable.Enabled = true;
            }
        }

        private void btnThreadInfo_Click(object sender, EventArgs e)
        {
            UpdateMessage(string.Format("线程数:{0}", _workThreadCount));
        }

        private void btnRestartForm_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.OK;
            if (rdbTask.Checked)
                _taskCancelToken.Cancel(true);
            Close();
            Dispose();
        }
    }
    View Code

     
    到底是选择ORM而不写Sql,还是 为了追求性能,而避开ORM,就看自己的情况来取舍了。

    选择一个组件的时候,可以考虑这几方面:稳定性、性能、易用性、是否保持更新、是否有较好的文档手册、使用者社区怎么样、是否开源

    上面提供的组件测试代码也可以看到这些组件的代码风格,喜欢语法糖的不妨好好看看,到底更喜欢哪种风格。

    综合考虑选择。

    各组件地址
    ClownFish:http://www.cnblogs.com/fish-li/ 【不开源】仅此一个是非ORM的。
    CYQ:http://www.cnblogs.com/cyq1162/ 【逐版本开源】
    EF: https://entityframework.codeplex.com/ 【开源】
    Moon:http://www.cnblogs.com/humble/ 【不开源】
    MySoft:http://www.cnblogs.com/maoyong/archive/2010/03/01/1675730.html 【逐版本开源】
    NHibernate:http://nhforge.org/ 【开源】
    PDF:http://www.cnblogs.com/bluedoctor/【开源】
    XCode:http://xcode.codeplex.com/ 【开源】
    希望更多的园友分享或开源自己所能知道的心爱的数据访问组件。

    QQ交流群:9524888 ,如果想提交测试代码,可以直接发给我,我加上去。

    更新修正说明:

    由于ClownFish提出测试的时候,使用了匿名对象,因此修改为SQL的直接执行,测试数据如下。

    由于1000线程的测试,在500左右,就出现连接超时问题,不能提供测试数据,有兴趣的朋友,自己运行测试。对此造成误解,请谅解。

    100-10 insert
    37-375-5
    215-611-29
    223-562-40
    12-181-3
    7-21-4
    10-138-3
    8-71-4
    11-187-4
    25-227-3
    107-829-3
    265-679-15
    226-609-19

    100-10-delete
    10-90-2
    24-115-3
    33-282-2
    37-174-3
    111-537-2
    23-203-2
    8-54-3

    100-10-update
    11-174-3
    16-190-4
    21-69-2
    21-58-4
    75-1155-3
     
  • 相关阅读:
    ArrayList removeRange方法分析
    LinkedHashMap源码分析(基于JDK1.6)
    LinkedList原码分析(基于JDK1.6)
    TreeMap源码分析——深入分析(基于JDK1.6)
    51NOD 2072 装箱问题 背包问题 01 背包 DP 动态规划
    51 NOD 1049 最大子段和 动态规划 模板 板子 DP
    51NOD 1006 最长公共子序列 Lcs 动态规划 DP 模板题 板子
    8月20日 训练日记
    CodeForces
    CodeForces
  • 原文地址:https://www.cnblogs.com/yelaiju/p/3209506.html
Copyright © 2011-2022 走看看