Entity Framework——性能测试
内容提要
一、对EF框架的性能测试
增、删、改,查测试及性能优化
二、使用sql执行
增、删、改,查测试
三、对以上两种方式对比分析
一 对EF框架的测试
1插入操作测试
测试代码(关键部分)
List<Collection> list = new List<Collection>();
int i = ;
while (i < count)
{
Collection cll = new Collection
{
Author = "test",
CitationNumber = ,
DiscNo = "CCNDTEMP",
Downloads = ,
FileName = "JSJJ20170803A030",
Period = "",
PublicationDate = DateTime.Now,
PublicationName = "江苏经济报",
PublisherUnit = "江苏经济报",
ResourceType = "报纸",
TableName = "CAINTEMP",
Title = "无人驾驶汽车2020年将量产",
Year = ""
};
list.Add(cll);
i++;
}
Stopwatch stw = new Stopwatch();
stw.Start();
db.Collections.AddRange(list);
stw.Stop();
var addTime = stw.ElapsedMilliseconds; Stopwatch stwS = new Stopwatch();
stwS.Start();
db.SaveChanges();
stwS.Stop();
var saveTime = stwS.ElapsedMilliseconds; Stopwatch stw = new Stopwatch();
stw.Start();
Parallel.ForEach(indexs, item =>
{
List<Collection> list = new List<Collection>();
int i = ;
while (i < oneCounts)
{
Collection cll = new Collection
{
Author = "test" + item,
CitationNumber = ,
DiscNo = "CCNDTEMP" + item,
Downloads = ,
FileName = "JSJJ20170803A030" + item,
Period = "",
PublicationDate = DateTime.Now,
PublicationName = "江苏经济报" + item,
PublisherUnit = "江苏经济报",
ResourceType = "报纸",
TableName = "CAINTEMP",
Title = "无人驾驶汽车2020年将量产",
Year = ""
};
list.Add(cll);
i++;
}
using (CustomDbContext db = new CustomDbContext())
{
db.Collections.AddRange(list);
db.SaveChanges();
}
});
stw.Stop();
var saveTime = stw.ElapsedMilliseconds
数据统计
单表(空表)单线程 |
插入数量(条) |
AddRange(ms) |
SaveChanges(ms) |
1000 |
741 |
2141 |
|
752 |
1672 |
||
742 |
1873 |
||
745 |
2145 |
||
757 |
1513 |
||
781 |
2732 |
||
10000 |
835 |
12797 |
|
826 |
14930 |
||
832 |
13421 |
||
835 |
11522 |
||
842 |
13963 |
||
832 |
11265 |
||
100000 |
4127 |
144663 |
|
3132 |
137083 |
||
1804 |
121466 |
||
单表(空表)10线程(最大并发数2),每个线程操作100条数据 |
1000 |
未计算 |
2102 |
1845 |
|||
1992 |
|||
2017 |
|||
2007 |
|||
单表(空表)10线程(最大并发数2),每个线程操作1000条数据 |
10000 |
未计算 |
6322 |
5480 |
|||
5285 |
|||
单表(空表)10线程(最大并发数2),每个线程操作10000条数据 |
100000 |
30071 |
|
28466 |
|||
30113 |
|||
单表(已有20万数据)10线程(最大并发数2),每个线程操作10000条数据 |
28638 |
||
单表(已有40万数据)10线程(最大并发数2),每个线程操作10000条数据 |
28932 |
||
单表(已有80万数据)10线程(最大并发数2),每个线程操作10000条数据 |
28982 |
||
单表(已有100万数据)10线程(最大并发数2),每个线程操作10000条数据 |
31049 |
2查询测试
测试代码(关键部分)
Stopwatch stw = new Stopwatch();
stw.Start();
var count = db.Collections.Where(m => m.Author == "test2").OrderBy(m => m.Id).ToList();
stw.Stop();
var time = stw.ElapsedMilliseconds;
数据统计
单表(已有200万数据),单条查找 |
查找说明 |
耗时(ms) |
执行DbSet<TEntity>.Find,查第100条 |
1728 |
|
1665 |
||
DbSet<TEntity>.Find,查第10000条 |
1668 |
|
1686 |
||
DbSet<TEntity>.Find,查第100000条 |
1664 |
|
1677 |
||
Queryable.FirstOrDefault(m => m.TableName ==CAINTEMP1) |
4951 |
|
4759 |
||
4771 |
||
Queryable.Where(m => m.Author ==test2) |
712 |
|
719 |
||
696 |
||
Queryable.Where(m => m.Author ==test2).Count() |
3921 |
|
3917 |
||
2957 |
||
3919 |
||
3734 |
||
Queryable.Where(m => m.Author ==test2).ToList() |
6841 |
|
7188 |
||
6907 |
||
7351 |
||
7335 |
||
7300 |
||
Queryable.Where(m => m.Author ==test2).OrderBy(m =>m.Id) |
719 |
|
711 |
||
706 |
||
Queryable.Where(m => m.Author ==test2).OrderBy(m =>m.Id).ToList() |
7823 |
|
7290 |
||
7385 |
3更新操作
测试代码(关键部分)
Stopwatch stw = new Stopwatch(); using (CustomDbContext db = new CustomDbContext()) { var collection = db.Collections.Find(); stw.Start(); collection.Author = "修改了作者"; db.Entry<Collection>(collection).State = System.Data.Entity.EntityState.Modified; db.SaveChanges(); } stw.Stop(); var time = stw.ElapsedMilliseconds; Stopwatch stw = new Stopwatch(); using (CustomDbContext db = new CustomDbContext()) { collections = db.Collections.Where(c => c.FileName == "JSJJ20170803A0301").ToList(); collections.RemoveRange(, ); stw.Start(); collections.ForEach(c => { c.Author = "修改了作者y"; db.Entry<Collection>(c).State = System.Data.Entity.EntityState.Modified; }); db.SaveChanges(); } stw.Stop(); var time = stw.ElapsedMilliseconds;
数据统计
单表(已有200万数据) |
操作 |
耗时(ms) |
更新一条 |
112 |
|
115 |
||
113 |
||
更新100条 |
42140 |
|
42520 |
||
更新1000条 |
407203 |
|
424386 |
4删除
测试代码(关键部分)
Stopwatch stw = new Stopwatch(); stw.Start(); List<CollectionUser> collections = null; using (CustomDbContext db = new CustomDbContext()) { collections = db.CollectionUsers.Where(c => c.Collection.FileName == "JSJJ20170803A0301").ToList(); collections.RemoveRange(, ); db.CollectionUsers.RemoveRange(collections); db.SaveChanges(); } stw.Stop(); var time = stw.ElapsedMilliseconds;
数据统计
单表(已有6万数据) |
操作 |
耗时(ms) |
删除1条记录 |
2080 |
|
1993 |
||
1926 |
||
删除100条 |
2824 |
|
3385 |
||
2480 |
||
删除400条 |
3005 |
|
删除500条 |
3526 |
5针对各种优化方案的测试
贪婪加载与延迟加载
开启延迟加载要满足两个条件:
1)在定时实体时,使用virtual,public or protected修饰实体的导航属性,不能使用sealed修饰。
2)使用默认的DbContextConfiguration.LazyLoadingEnabled配置,或将其设置为true
3)使用默认的DbContextConfiguration.ProxyCreationEnabled配置,或将其设置为true
若不满足上述两个条件则为贪婪加载
查询数据统计:
加载类型及说明 |
数据量 |
耗时(ms) |
贪婪加载(未使用导航属性) |
4003 |
2128 |
2120 |
||
2181 |
||
延迟加载(未使用导航属性) |
2102 |
|
2327 |
||
2064 |
||
延迟加载(使用导航属性) |
4003(关联导航属性在20000+) |
>10s |
分析
在数据量小的情况下,两种数据加载模式耗时基本相同,但当数据量较大,例如本次试验中关联导航属性记录数在2万以上时,延迟加载模式耗时巨大,因此适当关闭延迟加载可提高性能;延迟加载可以实现按需获取数据,这样客户端与服务端的传输数据量有可能减小,且也会相应地减少服务器端的内存消耗。
使用AsNoTracking()
查询数据统计
说明 |
检索条件 |
耗时 |
200万的数据表 |
Where(m => m.Author ==test2).OrderBy(m =>m.Id).ToList() |
9440 |
7232 |
||
9086 |
||
7435 |
||
7637 |
分析
使用AsNoTracking()第一次查询较慢,第二次比不使用AsNoTracking()快一点,不过性能提高不大。
设置IsUnicode
IsUnicode(false)则在code first模式下,string类型实体字段对应着varchar类型的表字段,
若不配置或IsUnicode(true),则对应着text类型的。
IsUnicode设置 |
检索条件 |
表字段类型 |
耗时(ms) |
true |
AsNoTracking(),Queryable.Where(m => m.Author ==test2).OrderBy(m =>m.Id).ToList() |
varchar |
8407 |
10952 |
|||
8528 |
|||
8674 |
|||
10492 |
|||
11685 |
|||
7659 |
分析
对于EF6来说,是否使用IsUnicode对查询速度基本没有影响。之前的版本会产生类型转换的问题,但实测来看EF6不会。
二 使用sql和MySql.Data.dll
1 添加
测试代码(关键部分)
Stopwatch stw = new Stopwatch(); stw.Start(); int loop = ; Collection cll = new Collection { Author = "test", CitationNumber = , DiscNo = "CCNDTEMP", Downloads = , FileName = "JSJJ20170803A030", Period = "", PublicationDate = DateTime.Now, PublicationName = "江苏经济报", PublisherUnit = "江苏经济报", ResourceType = "报纸", TableName = "CAINTEMP", Title = "无人驾驶汽车2020年将量产", Year = "" }; string values = "(@FileName0, @Title0, @TableName0, @DiscNo0, @ResourceType0, @Downloads0, @CitationNumber0, @Author0, @PublicationName0, @PublisherUnit0, @PublicationDate0, @Year0, @Period0)"; Parameters param = new Parameters(); for (int i = ; i < loop; i++) { if (i < loop-) { values = values + "," + string.Format("(@FileName{0}, @Title{0}, @TableName{0}, @DiscNo{0}, @ResourceType{0}, @Downloads{0}, @CitationNumber{0}, @Author{0}, @PublicationName{0}, @PublisherUnit{0}, @PublicationDate{0}, @Year{0}, @Period{0})" , i+); } param.AddParameter("@FileName"+i, MySqlDbType.VarChar, , cll.FileName); param.AddParameter("@Title" + i, MySqlDbType.VarChar, , cll.Title); param.AddParameter("@TableName" + i, MySqlDbType.VarChar, , cll.TableName); param.AddParameter("@DiscNo" + i, MySqlDbType.VarChar, , cll.DiscNo); param.AddParameter("@ResourceType" + i, MySqlDbType.VarChar, , cll.ResourceType); param.AddParameter("@Downloads" + i, MySqlDbType.Int32, , cll.Downloads); param.AddParameter("@CitationNumber" + i, MySqlDbType.Int32, , cll.CitationNumber); param.AddParameter("@Author" + i, MySqlDbType.VarChar, , cll.Author); param.AddParameter("@PublicationName" + i, MySqlDbType.VarChar, , cll.PublicationName); param.AddParameter("@PublisherUnit" + i, MySqlDbType.VarChar, , cll.PublisherUnit); param.AddParameter("@PublicationDate" + i, MySqlDbType.DateTime, , cll.PublicationDate); param.AddParameter("@Year" + i, MySqlDbType.VarChar, , cll.Year); param.AddParameter("@Period" + i, MySqlDbType.VarChar, , cll.Period); } string sql = @"INSERT INTO collections (`FileName`, `Title`, `TableName`, `DiscNo`, `ResourceType`, `Downloads`, `CitationNumber`, `Author`, `PublicationName`, `PublisherUnit`, `PublicationDate`, `Year`, `Period`) VALUES"+values; stw.Stop(); var addTime = stw.ElapsedMilliseconds; Stopwatch stwS = new Stopwatch(); stwS.Start(); MySqlService service = new MySqlService("database=noef_testdb;server=192.168.107.13;uid=root;pwd=cnki2017;port=3306;Character Set=utf8;"); service.ExecuteNonQuery(sql, param); stwS.Stop(); var saveTime = stwS.ElapsedMilliseconds;
数据统计
单表(空表)单线程 |
插入数量(条) |
数据拼接(ms) |
INSERT ExecuteNonQuery(ms) |
1000 |
93 |
235 |
|
94 |
227 |
||
92 |
229 |
||
10000 |
14521 |
851 |
|
14695 |
851 |
||
14825 |
857 |
||
单表(空表)10线程(最大并发数2),每个线程操作1000条数据 |
10000 |
14762(仅拼接一次的时间,即10000条) |
2870 |
2866 |
|||
2682 |
|||
单表(已有50万数据)10线程(最大并发数2),每个线程操作1000条数据 |
14808(仅拼接一次的时间,即10000条) |
2643 |
|
单表(已有80万数据)10线程(最大并发数2),每个线程操作1000条数据 |
15066(仅拼接一次的时间,即10000条) |
2665 |
2 读取
测试代码(关键部分)
Stopwatch stwS = new Stopwatch(); stwS.Start(); string sql = @"select * from collections where Author ='test2' order by Id DESC"; MySqlService service = new MySqlService("database=ef_testdb;server=192.168.107.13;uid=root;pwd=cnki2017;port=3306;Character Set=utf8;"); service.ExecuteReader(sql); stwS.Stop(); var saveTime = stwS.ElapsedMilliseconds;
数据统计
单表(已有200万数据),单条查找 |
查找条件 |
耗时(ms) |
Id =100000 |
170 |
|
159 |
||
158 |
||
单表(已有200万数据),查找多条 |
FileName ='JSJJ20170803A0301' |
5403 |
4247 |
||
3613 |
||
FileName ='JSJJ20170803A0301' order by Id DESC |
10904 |
|
8941 |
||
7265 |
||
6633 |
||
7048 |
||
Author ==test2 order by Id DESC |
12958 |
|
8619 |
||
8481 |
||
8030 |
3 更新
测试代码(关键部分)
Stopwatch stwS = new Stopwatch(); stwS.Start(); string sql = "UPDATE collections SET Author = '不使用EF' WHERE Id =10000"; MySqlService service = new MySqlService("database=ef_testdb;server=192.168.107.13;uid=root;pwd=cnki2017;port=3306;Character Set=utf8;"); service.ExecuteNonQuery(sql); stwS.Stop(); var saveTime = stwS.ElapsedMilliseconds;
数据统计
单表(已有200万数据) |
sql |
耗时(ms) |
(多条跟新)UPDATE SET Author = '不使用EF' WHERE FileName ='JSJJ20170803A0301' |
229 |
|
171 |
||
172 |
||
(单条更新)UPDATE SET Author = '不使用EF' WHERE Id =10000 |
307 |
|
194 |
||
218 |
||
197 |
4 删除
测试代码(关键部分)
Stopwatch stwS = new Stopwatch(); stwS.Start(); string sql = @"delete `collectionusers` from `collectionusers`,`collections` where `collections`.`Id` = `collectionusers`.`Collection_Id` and collections.FileName ='JSJJ20170803A0301'"; MySqlService service = new MySqlService("database=ef_testdb;server=192.168.107.13;uid=root;pwd=cnki2017;port=3306;Character Set=utf8;"); service.ExecuteNonQuery(sql); stwS.Stop(); var saveTime = stwS.ElapsedMilliseconds;
数据统计
单表(已有6万数据) |
sql |
耗时(ms) |
delete from collectionusers where Id = 320 |
198 |
|
175 |
||
221 |
||
(单条更新)UPDATE SET Author = '不使用EF' WHERE Id =10000 |
307 |
|
194 |
||
218 |
||
197 |
||
UPDATE SET Author = '不使用EF' WHERE Id =10000(未找到,而未删除成功) |
195 |
|
194 |
||
202 |
||
(删除2000+条记录)delete `collectionusers` from `collectionusers`,`collections` where `collections`.`Id` = `collectionusers`.`Collection_Id` and collections.FileName ='JSJJ20170803A0301' |
370 |
三 对比分析
测试环境:
两台机器A和B,A是测试程序运行机器,B是Mysql运行机器,A和B在局域网内。
A
B
AB及网络对结果的影响:
AB机器之间的网络通信耗费一定的时间,但局域网内一般很小,且不单纯看执行时间,单纯看执行时间意义不大,本测试目的是通过比较研究EF框架的性能,另外实际的系统部署中,也不会将应用与数据库部署到同一台机器。
每中操作执行3~6次左右,如果发现某次执行时间过长或过短会多执行几次,严格来讲,只有统计数据的数量达到一定程度才能得出比较接近事实的结论,但这里在满足一定条件的前提下,例如:保持网络状态良好,保持机器运行良好,保证测试程序正确,在这样的前提下减少测试次数也可以得出比较接近事实的结论;在统计分析中没有将所有数据加一对比,也没有采用取平均值等方式,因为只是想从数量级上来加以对比。
1 添加操作
数据量 |
使用EF框架 |
Sql+MySql.Data.dll(简写NOEF) |
结论 |
说明 |
1000 |
741+2141 |
93+235 |
大致相差一个数量级 |
空表,单线程 |
10000 |
826+14930 |
14521+851 |
大致相等 |
分析
插入数据量是1000时相差了一个数量级,而数据量为10000为花费时间大致相等,由统计数据可见耗时主要是对待插入数据的处理,实际的数据库操作还是相当快的,所以在实际应用过程中,如果代码实现的不好,那么可能比使用EF框架的读写性能还差,好在对待插入数据的处理优化比较容易。
数据量 |
使用EF框架 |
Sql+MySql.Data.dll(简写NOEF) |
结论 |
说明 |
10000 |
6322 |
14521+851 |
大致相差一个数量级,但实际使用不会这么大 |
空表,EF框架10线程,最大并发数2; NoEF单线程 |
分析
使用EF框架同时使用多线程改进插入速度,并发数为2时,性能大致提升一倍;相比NoEF单线程而言性能已相差无几,当然,并不是任何时候都可以使用多线程来提高读写速度。
数据量 |
使用EF框架 |
Sql+MySql.Data.dll(简写NOEF) |
结论 |
说明 |
100000 |
28982 |
15066(一次)+2665 |
大致相差一个数量级,但实际使用不会这么大 |
表已有数据80万,10线程,最大并发数2; |
分析
两种方式都是都是10线程,数据插入速度大致相差一个数量级,考虑到NOEF方式下要处理数据的问题,那么性能相差就没有这么大了,其实实际的应用也与这种情况是相似的。
2 查找
数据量 |
使用EF框架 |
Sql+MySql.Data.dll(简写NOEF) |
结论 |
说明 |
一条 |
1669 |
170 |
单纯的多条查找性能基本相同, |
表已有200万数据,检索条件相同 |
多条 |
7823 |
5403 |
||
719 |
12958 |
检索条件相同,但使用ToList() |
分析
当检索一条时并且使用Id值,检索速度相差一个数量级;而查找多条时,性能基本相同,然而会发现一个奇怪的现象,就是使用EF对检索结果ToList()与不转换,耗时相差较大。
3 更新
数据量 |
使用EF框架 |
Sql+MySql.Data.dll(简写NOEF) |
结论 |
说明 |
一条 |
112 |
307 |
总体上EF更新性能比NOEF查得多 |
表已有200万数据 |
多条 |
407203 |
229 |
分析
更新一条数据EF反而比NOEF要快,但是相差也不多,可以判定性能基本一致;当更新多条时,NOEF性能明显比EF框架好,相差几个数量级。
4 删除
数据量 |
使用EF框架 |
Sql+MySql.Data.dll(简写NOEF) |
结论 |
说明 |
一条 |
2080 |
221 |
删除操作EF耗时与NOEF相差一个数量级,然而多条操作 |
表已有6万数据 删除多条时,NOEF方式下一次删除2000+条记录,而EF方式下删除500条记录 |
多条 |
407203 |
370 |
分析
从NOEF方式下一次删除2000+条记录,而EF方式下删除500条记录这一结果来看,NOEF性能明显优于EF,且NOEF方式下,删除操作耗时随删除数据量平稳增长且增长率很小;但EF操作耗时随操作数据量增大而明显增大;另外,当NOEF方式下,没有找到数据而不能删除数据时,耗时202左右,也就是说数据量很小时,譬如删除几条或十几条操作时间基本等同于查询时间。
-----------------------------------------------------------------------------------------
转载与引用请注明出处。
时间仓促,水平有限,如有不当之处,欢迎指正。
Entity Framework——性能测试的更多相关文章
- Entity Framework与ADO.NET批量插入数据性能测试
Entity Framework是.NET平台下的一种简单易用的ORM框架,它既便于Domain Model和持久层的OO设计,也提高了代码的可维护性.但在使用中发现,有几类业务场景是EF不太擅长的, ...
- 一个Entity Framework、ADO.NET查询性能测试
Entity Framework自然是会比ADO.NET性能慢点,这个不多说了.直接上结果. 本该用测试项目的,不过我建了个aspx.下面是随便测20遍得到的结果 补充!!把12行改成 list = ...
- Entity Framework Code First+SQL Server,改变聚集索引,提高查询性能
.net Entity Framework(调研的是Entity Framework 4.0) code first方式生成数据库时,不能修改数据库表的索引,而SQLServer默认会把数据表的主键设 ...
- ORM系列之Entity FrameWork详解
一. 谈情怀 从第一次接触开发到现在(2018年),大约有六年时间了,最初阶段连接数据库,使用的是[SQL语句+ADO.NET],那时候,什么存储过程.什么事务 统统不理解,生硬的将SQL语句传入SQ ...
- 细说ORM之Entity FrameWork系列(被替换)
一. 谈情怀 从第一次接触开发到现在(2018年),接近五年时间了,最初阶段连接数据库,使用的是[SQL语句+ADO.NET],那时候,什么存储过程.什么事务 统统不理解,生硬的将SQL语句传入SQL ...
- ASP.NET MVC深入浅出系列(持续更新) ORM系列之Entity FrameWork详解(持续更新) 第十六节:语法总结(3)(C#6.0和C#7.0新语法) 第三节:深度剖析各类数据结构(Array、List、Queue、Stack)及线程安全问题和yeild关键字 各种通讯连接方式 设计模式篇 第十二节: 总结Quartz.Net几种部署模式(IIS、Exe、服务部署【借
ASP.NET MVC深入浅出系列(持续更新) 一. ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态模 ...
- ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第二章:利用模型类创建视图、控制器和数据库
在这一章中,我们将直接进入项目,并且为产品和分类添加一些基本的模型类.我们将在Entity Framework的代码优先模式下,利用这些模型类创建一个数据库.我们还将学习如何在代码中创建数据库上下文类 ...
- Entity Framework Core 1.1 升级通告
原文地址:https://blogs.msdn.microsoft.com/dotnet/2016/11/16/announcing-entity-framework-core-1-1/ 翻译:杨晓东 ...
- Entity Framework Core 实现MySQL 的TimeStamp/RowVersion 并发控制
将通用的序列号生成器库 从SQL Server迁移到Mysql 遇到的一个问题,就是TimeStamp/RowVersion并发控制类型在非Microsoft SQL Server数据库中的实现.SQ ...
随机推荐
- log4js日志
安装log4js:npm install log4js express中配置log4js中间件: var log = require("./modules/utils/logUtil.js& ...
- mycat核心概念
一.逻辑库(schema) 业务人员一般是不需要知道数据库中间件的,他们只需要连接到数据库并使用数据库,一切复杂的细节都被中间件给隐藏了,对于业务人员来说中间件即是一个数据库.这里逻辑库的概念就是一个 ...
- GIT学习笔记——第一章
git之vim编辑器退出命令 # 学习笔记 张文军微博主页 张文军码云主页 张文军新浪云主页 张文军博客主页 ## 刚学习git,好多东西没接触过,进入vim后不知道如何出来了,网上找了很多都 ...
- Spring_Spring与IoC_基于XML的DI
一.注入分类 bean实例在调用无参构造器创建空值对象后,就要对Bean对象的属性进行初始化.初始化时由容器自动完成的,称为注入.根据注入方式的不同,常用的有2类:设值注入.构造注入.(还有一种,实现 ...
- JS埋点 小结
今天在看<大型网站性能监测.分析与优化>一书,提到性能监测方式,才知道有这个名词 “JS埋点”. 大概作用:通过在web页面中,添加js脚本,实现对页面性能监测(如加载时间.服务器响应时间 ...
- BBS需求分析和orm设计
一.BBS博客需求分析 首页(现实文章) 文章详情 点赞 文章评论(子评论,评论的展示) 登录功能(图片验证码) 注册功能(基于form验证) 个人站点(不同人不同样式,文章过滤) 后台管理(文章展示 ...
- javascript获取文件后缀名
javascript获取文件后缀名:在需要验证文件格式的时候,首先就要获得文件的格式,下面是一个通过正则表达式获取文件后缀名的一个简单实例. function validate(){ var impo ...
- div,css&table布局有哪些区别
DIV+CSS布局与TABLE布局相比,有哪些优点? 1.代码少,页面文件小,下载快 Div+css的布局现在属于国际W3C标准,table不是. 都知道用div的布局代码肯定少,所有的样式都在CSS ...
- ntp时钟服务器
NTP服务器时钟校准的基本流程: (1):NTP客户端向NTP服务器发出一个时间请求包(UDP包),其中包含了该包离开客户端时的时间戳. (2):当服务器接收到该包时.填入包到达时的时间戳.包离开时的 ...
- 如何优雅地使用Markdown (Sublime 3 + MarkdownEditing+OmniMarkupPreviewer)
最近开始上手Sublime 3 作为Markdown 的重度使用者自然关于Markdown的插件是必不可少的 . 在这里记录分享一下我常用的两款Markdown插件. MarkdownEditing ...