博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
测试 ClownFish、CYQ、Entity Framework、Moon、MySoft、NHibernate、PDF、XCode数据访问组件性能...
阅读量:5915 次
发布时间:2019-06-19

本文共 25238 字,大约阅读时间需要 84 分钟。

下期预告:

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

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

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

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

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

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

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

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

源码下载:

git地址:  欢迎园友贡献改进代码。

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

 

默认测试数据库使用SqlServer

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

CREATE 
TABLE 
[
dbo
].
[
Test
]
(
    
[
RowId
] 
[
int
] 
IDENTITY(
1,
1
NOT 
NULL,
    
[
Guid
] 
[
varchar
](
50
primary 
key 
NOT 
NULL,
    
[
Content
] 
[
nvarchar
](
500
NULL,
    
[
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性能其实并没有一般人想象的那么糟糕。

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

项目目录

测试代码接口

ExpandedBlockStart.gif
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测试代码

ExpandedBlockStart.gif
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测试代码
ExpandedBlockStart.gif
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测试代码

ExpandedBlockStart.gif
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测试代码

ExpandedBlockStart.gif
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测试代码

ExpandedBlockStart.gif
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测试代码

ExpandedBlockStart.gif
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测试代码

ExpandedBlockStart.gif
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测试代码

ExpandedBlockStart.gif
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测试代码
ExpandedBlockStart.gif
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测试代码

ExpandedBlockStart.gif
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

测试耗时监控

ExpandedBlockStart.gif
///
 
///
 执行指定查询的测试,并记录测试数据
///
 
///
 线程序号
///
 执行的查询
///
 执行测试的组件实体
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多行,慎点。

ExpandedBlockStart.gif
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 + 
"
\n
");
            rtxtMessage.Select(rtxtMessage.Text.Length - 
1
1);
            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: 【不开源】仅此一个是非ORM的。
CYQ: 【逐版本开源】
EF: 【开源】
Moon: 【不开源】
MySoft: 【逐版本开源】
NHibernate: http://nhforge.org/ 【开源】
PDF: 【开源】
XCode: 【开源】
希望更多的园友分享或开源自己所能知道的心爱的数据访问组件。

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
 

 

转载地址:http://nrgpx.baihongyu.com/

你可能感兴趣的文章
acctmod-bugzilla.sh
查看>>
LigerUI - 树表格的数据来自Server
查看>>
mysql获取7天前数据,日期比较
查看>>
virtualbox 在windows7上安装
查看>>
iOS Http请求异步请求
查看>>
char、varchar 如何设置索引的长度?
查看>>
git日常使用
查看>>
初体验Jenkins安装并进行Maven项目自动化部署
查看>>
GNOME 3.2 发布
查看>>
实现sso 的两种方案
查看>>
【汇编】C++ 函数调用之——有参无返回调用(传引用)
查看>>
【汇编】C++递归调用实现
查看>>
maven 项目,通过maven编译 解决出现JSP NullPointerException
查看>>
log4j2之简化封装,告别静态成员变量
查看>>
Notadd 应用配置数据导入导出设计
查看>>
插件学习:metisMenu.min.js
查看>>
GitHub 开源的 MySQL 在线更改 Schema 工具
查看>>
(转) Twisted :第十六部分 Twisted 进程守护
查看>>
python3 使用threading模块进行多线程编码实现
查看>>
Java String和Date的转换
查看>>