提高C++性能的编程技术笔记:标准模板库+测试代码
标准模板库(Standard Template Library, STL)是容器和通用算法的强效组合。
渐近复杂度:算法的渐近复杂度是对算法性能的近似估计。它是算法集到特定性能标准集的映射。如果需要对包含N个整数的向量的所有元素求和,那么每个整数必须且仅需检查一次,因此该算法的复杂度约为N,我们将其称为O(N)。另一方面,假设需要创建一个包含N个元素的向量,由于某种原因,你需要将这些元素插入到该向量的前端。然而,在向量的前端每插入一个元素便会迫使所有已存在的元素移动1个位置。这就导致了(1+2+3+…+N)次向量元素的移动,也即(N/2)(N+1)次移动。即使需要移动(N*N/2)+(N/2)次,但我们仍说这个算法的复杂度是O(N*N)。这是因为渐近性能标准集将忽略常量倍数和低阶因子。因而N*N和7N*N的复杂度相同:均为O(N*N)。STL对其算法渐近复杂度的保证是一个良好的开端。它告诉我们,所使用的算法是同类算法中最好的。
插入:在集合大小事先可知的情况下,在尾部进行元素插入操作,速度,数组>向量>双向列表>多重集。数组和向量均为占用连续内存块的顺序容器。当无法事先确定集合大小时,向量将会更有用。向量是可以动态增长的,这样程序员就不用考虑集合的大小。向量的大小是指向量当前拥有元素的数量。向量的容量是指向量能够容纳元素数量的最大值,超过这个值,向量就必须分配更多的内存以适应元素的增长。当往向量中插入第一个元素时,为了使向量的容量超过它的初始大小(值为1),典型的STL实现将会分配一大块内存。后续的插入将会增加向量的大小,而容量保持不变。如果集合持续增长,那么向量大小最终将会达到它的容量。下一次插入操作将会迫使向量的实现扩大自身容量。这必须包含以下几个步骤:(1). 分配更大的内存块,以便为增加的元素留出空间;(2). 将当前集合中现存的所有元素复制到新分配的内存中。在该过程中,会为旧集合的每一个元素调用拷贝构造函数;(3). 销毁旧集合并释放它所占用的空间。在该过程中,会为旧集合中的每一个元素调用析构函数。这些步骤可能会引起巨额开销。因此,我们希望尽可能少地出现向量大小超过其容量的情况。列表容器并未将元素存储在连续的内存空间中,所以也就无须应付容量问题和相关的性能开销问题。向量容器在进行前端插入时的性能极其槽糕。而列表在进行前端插入或后端插入时性能几乎一致。
删除:删除操作的性能情况在很多方面都与插入操作很类似。很多关于插入效率的结论同样适用于删除。例如:(1). 向量擅长于在尾部对元素进行插入(或删除)操作。因为这种操作与集合大小无关,所以它是一种固定时间的操作。(2). 除了尾部操作之外,采用向量进行其它任何位置的插入(或删除)操作都是一种极为糟糕的选择。这种插入(或删除)的代价与插入(或删除)点到向量的最后一个元素之间的距离成正比例。(3). 双向队列在集合的前端和尾部插入(或删除)元素时效率很高(常数时间),在其它任何位置插入(或删除)元素时效率都很低。(4). 列表在集合的任何位置插入(或删除)元素时效率都很高(固定时间)。
遍历:对于容器的遍历操作来说,向量和数组的性能是相同的。它们均远胜过列表。容器遍历的关键因素似乎为容器内存布局和系统缓存之间的交互作用。
查找:当进行元素查找时,使用成员find方法,多重容器可以胜过其它的所有竞争对手。而多重集是有序集,这使其在插入和删除操作上遭受了一些性能上的损失。但是,从另一方面来看,有序特性也为多重集容器在查找方面带来了巨大的优势。
函数对象:默认情况下,accumulate()函数将operator+操作应用到容器中所有元素,然后返回这些元素相加的累计结果。对于整数集合来说,如果提供给accumulate()函数的初始值为0,那么该函数返回的结果就是集合中所有元素的和。accumulate()函数不仅可以进行对象相加,而且可以对容器元素进行任何操作(前提是元素支持这种操作),然后返回累计结果。函数指针直到运行时才能被解析,这就使得它们无法被内联。而函数对象是在编译时被确定的,这就使得编译器可以自由地内联operator()函数并显著地提升效率。
STL实现在以下几个方面形成了自己的优势:(1). STL实现使用最好的算法;(2). STL实现的设计者非常有可能是领域内的专家;(3). 这些领域内的专家完全地致力于提供一个灵活、强大并且高效的库。这是他们的首要任务。
STL是抽象、灵活性和效率的一种罕见的结合。对于某种特定的应用模式,一些容器比其它的更加高效,这都要随着实际应用而定。除非了解一些相关领域内STL所忽略的问题,否则你是不可能超过STL实现的。不过,在一些特定的情况下,还是有可能超越STL实现的性能的。
以下是测试代码(standard_template_library.cpp):
#include "standard_template_library.hpp"
#include <cstdlib>
#include <iostream>
#include <chrono>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <algorithm>
#include <ctime>
#include <memory>
#include <numeric>
#include <functional>namespace standard_template_library_ {// reference: 《提高C++性能的编程技术》:第十一章:标准模板库
namespace {
template<class T>
void arrayInsert(T* a, const T* collection, int size)
{for (int k = 0; k < size; ++k) {a[k] = collection[k];}
}template<class T>
void arrayTraverse(const T* a, int size)
{T sum = std::accumulate(&a[0], &a[size], 0);
}template<class T>
void arrayFind(const T* a, const T* collection, int size)
{T const value = collection[size/2];T* tmp = const_cast<T*>(a);T* p = std::find(&tmp[0], &tmp[size], value);
}template<class T>
void vectorInsert(std::vector<T>* v, const T* collection, int size)
{for (int k = 0; k < size; ++k) {v->push_back(collection[k]);}
}template<class T>
void vectorInsertFront(std::vector<T>* v, const T* collection, int size)
{for (int k = 0; k < size; ++k) {v->insert(v->begin(), collection[k]);}
}template<class T>
void vectorDelete(std::vector<T>* v)
{while (!v->empty()) {v->pop_back();}
}template<class T>
void vectorDeleteFront(std::vector<T>* v)
{while (!v->empty()) {v->erase(v->begin());}
}template<class T>
void vectorTraverse(const std::vector<T>* v, int size)
{T sum = std::accumulate(v->cbegin(), v->cend(), 0);
}template<class T>
void vectorFind(const std::vector<T>* v, const T* collection, int size)
{T const value = collection[size/2];auto it = std::find(v->cbegin(), v->cend(), value);
}template<class T>
void listInsert(std::list<T>* l, const T* collection, int size)
{for (int k = 0; k < size; ++k) {l->push_back(collection[k]);}
}template<class T>
void listInsertFront(std::list<T>* l, const T* collection, int size)
{for (int k = 0; k < size; ++k) {l->push_front(collection[k]);}
}template<class T>
void listDelete(std::list<T>* l)
{while (!l->empty()) {l->pop_back();}
}template<class T>
void listDeleteFront(std::list<T>* l)
{while (!l->empty()) {l->pop_front();}
}template<class T>
void listTraverse(const std::list<T>* l, int size)
{T sum = std::accumulate(l->cbegin(), l->cend(), 0);
}template<class T>
void listFind(const std::list<T>*l, const T* collection, int size)
{T const value = collection[size/2];auto it = std::find(l->cbegin(), l->cend(), value);
}template<class T>
void multisetInsert(std::multiset<T>* s, const T* collection, int size)
{for (int k = 0; k < size; ++k) {s->insert(collection[k]);}
}template<class T>
void multisetFind(const std::multiset<T>* s, const T* collection, int size)
{T const value = collection[size/2];// 当查找多重集容器时,使用std::find并不是最佳的选择//auto it = std::find(s->cbegin(), s->cend(), value);auto it = s->find(value);
}int* genIntData(int size)
{std::srand(std::time(nullptr));int* data = new int[size];std::generate(&data[0], &data[size], std::rand);return data;
}int mult(int x, int y)
{return (x*y);
}class Mult {
public:int operator()(int x, int y) const { return (x*y); }
};} // namespaceint test_standard_template_library_1()
{std::chrono::high_resolution_clock::time_point time_start, time_end;const int count{400000}, count2{10000}, count3{200000000};int* data = genIntData(count);{ // normal array insert back operationstd::unique_ptr<int[]> arr(new int[count]); time_start = std::chrono::high_resolution_clock::now();arrayInsert(arr.get(), data, count);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "first value: %d, array insert back time spend: %f seconds\n",arr.get()[0], (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // vector insert back operationstd::vector<int> vec; time_start = std::chrono::high_resolution_clock::now();vectorInsert(&vec, data, count);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "first value: %d, vector insert back time spend: %f seconds\n",vec[0], (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // list insert back operationstd::list<int> l; time_start = std::chrono::high_resolution_clock::now();listInsert(&l, data, count);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "first value: %d, list insert back time spend: %f seconds\n",*(l.cbegin()), (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // multiset insert back operationstd::multiset<int> s; time_start = std::chrono::high_resolution_clock::now();multisetInsert(&s, data, count);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "first value: %d, multiset insert back time spend: %f seconds\n",*(s.cbegin()), (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // vector insert front operationstd::vector<int> vec; time_start = std::chrono::high_resolution_clock::now();vectorInsertFront(&vec, data, count);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "first value: %d, vector insert front time spend: %f seconds\n",vec[0], (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // list insert front operationstd::list<int> l; time_start = std::chrono::high_resolution_clock::now();listInsertFront(&l, data, count);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "first value: %d, list insert front time spend: %f seconds\n",*(l.cbegin()), (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // vector delete back operationstd::vector<int> vec(data, data+count);time_start = std::chrono::high_resolution_clock::now();vectorDelete(&vec);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "vector size: %d, vector delete back time spend: %f seconds\n",vec.size(), (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // list delete back operationstd::list<int> l(data, data+count); time_start = std::chrono::high_resolution_clock::now();listDelete(&l);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "list size: %d, list delete back time spend: %f seconds\n",l.size(), (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // vector delete front operationstd::vector<int> vec(data, data+count);time_start = std::chrono::high_resolution_clock::now();vectorDeleteFront(&vec);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "vector size: %d, vector delete front time spend: %f seconds\n",vec.size(), (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // list delete front operationstd::list<int> l(data, data+count); time_start = std::chrono::high_resolution_clock::now();listDeleteFront(&l);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "list size: %d, list delete front time spend: %f seconds\n",l.size(), (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // normal array traverse operationtime_start = std::chrono::high_resolution_clock::now();for (int i = 0; i < count2; ++i)arrayTraverse(data, count);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "first value: %d, array traverse time spend: %f seconds\n",data[0], (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // vector traverse operationstd::vector<int> vec(data, data+count);time_start = std::chrono::high_resolution_clock::now();for (int i = 0; i < count2; ++i)vectorTraverse(&vec, count);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "first value: %d, vector traverse time spend: %f seconds\n",vec[0], (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // list traverse operationstd::list<int> l(data, data+count); time_start = std::chrono::high_resolution_clock::now();for (int i = 0; i < count2; ++i)listTraverse(&l, count);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "first value: %d, list traverse time spend: %f seconds\n",*l.cbegin(), (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // normal array find operationtime_start = std::chrono::high_resolution_clock::now();for (int i = 0; i < count2; ++i)arrayFind(data, data, count);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "first value: %d, array find time spend: %f seconds\n",data[0], (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // vector find operationstd::vector<int> vec(data, data+count);time_start = std::chrono::high_resolution_clock::now();for (int i = 0; i < count2; ++i)vectorFind(&vec, data, count);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "first value: %d, vector find time spend: %f seconds\n",vec[0], (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // list find operationstd::list<int> l(data, data+count); time_start = std::chrono::high_resolution_clock::now();for (int i = 0; i< count2; ++i)listFind(&l, data, count);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "first value: %d, list find time spend: %f seconds\n",*l.cbegin(), (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // multiset find operationstd::multiset<int> s; time_start = std::chrono::high_resolution_clock::now();for (int i = 0; i < count2; ++i)multisetFind(&s, data, count);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "first value: %d, multiset find time spend: %f seconds\n",*(s.cbegin()), (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}int a[10] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 23};int init = 1, product = 0;{ // accumulate operation: function pointer time_start = std::chrono::high_resolution_clock::now();for (int i = 0; i < count3; ++i)product = std::accumulate(&a[0], &a[10], init, mult);time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "value: %d, accumulate function pointer time spend: %f seconds\n",product, (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // accumulate operation: function objecttime_start = std::chrono::high_resolution_clock::now();for (int i = 0; i < count3; ++i)product = std::accumulate(&a[0], &a[10], init, Mult());time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "value: %d, accumulate function object time spend: %f seconds\n",product, (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}{ // accumulate operation: function object(std) time_start = std::chrono::high_resolution_clock::now();for (int i = 0; i < count3; ++i)product = std::accumulate(&a[0], &a[10], init, std::multiplies<int>());time_end = std::chrono::high_resolution_clock::now(); fprintf(stdout, "value: %d, accumulate function object(std) time spend: %f seconds\n",product, (std::chrono::duration_cast<std::chrono::duration<double>>(time_end-time_start)).count());
}delete [] data;return 0;
}} // namespace standard_template_library_
执行结果如下:
GitHub:https://github.com/fengbingchun/Messy_Test
相关文章:

「创式纪」人工智能应用创新大赛启动,首次结合商业计划和机器学习
谈到人工智能,技术和应用场景成为了大家广泛关注的话题。技术的演进,是推动人工智能发展的核心,而广泛的场景应用,则是人工智能真正价值所在。现阶段,精准营销、信贷风控、人脸比对等为人熟知的AI,已经经过…

linux chattr命令
chattr 设置linux文件的属性 (参照man手册进行翻译,常用的属性都翻译过来,个人觉得很少用到的属性就没有翻译) 用法:chattr [ -RVf ] -[acdeijstuADST] files选项:-R 对目录进行递归处理-V 显示详细的输出-F 忽略…

swift 中高德地图随时读取坐标地点的写法
自己写的方法 不比比 自己能看懂就行 只用作自己学习swift的总结 import UIKit typealias block (String,String) ->() class MoveCarViewController: UIViewController,MAMapViewDelegate,AMapLocationManagerDelegate,AMapSearchDelegate,UITextFieldDelegate,UIAler…

万字干货 | Python后台开发的高并发场景优化解决方案
嘉宾 | 黄思涵 来源 | AI科技大本营在线公开课互联网发展到今天,规模变得越来越大,也对所有的后端服务提出了更高的要求。在平时的工作中,我们或多或少都遇到过服务器压力过大问题。针对该问题,本次公开课邀请到了金山办公AI平台研…

提高C++性能的编程技术笔记:引用计数+测试代码
引用计数(reference counting):基本思想是将销毁对象的职责从客户端代码转移到对象本身。对象跟踪记录自身当前被引用的数目,在引用计数达到零时自行销毁。换句话说,对象不再被使用时自行销毁。 引用计数和执行速度之间的关系是与上下文紧密…

如何提升 CSS 选择器的性能?
CSS选择器对性能的影响源于浏览器匹配选择器和文档元素时所消耗的时间,所以优化选择器的原则是应尽量避免使用消耗更多匹配时间的选择器。而在这之前我们需要了解CSS选择器匹配的机制, 如子选择器规则: #header > a {font-weight:blod;} 我…

百度AI攻坚战:PaddlePaddle中国突围
作者 | 阿司匹林出品 | AI科技大本营(ID:rgznai100)2013年,百度开始研发深度学习框架PaddlePaddle,搜索、凤巢CTR预估上线DNN模型。2016年,在百度世界大会上,百度宣布PaddlePaddle开源ÿ…

提高C++性能的编程技术笔记:编码优化+测试代码
缓存:在现代处理器中,缓存经常与处理器中的数据缓存和指令缓存联系在一起。缓存主要用来存储使用频繁而且代价高昂的计算结果,这样就可以避免对这些结果的重复计算。如,循环内对常量表达式求值是一种常见的低性能问题。 预先计算…

Swift 中使用 SQLite——打开数据库
关于Swift中使用SQLite,接下来可能会分别从打开、增、删、改、查,几个方面来介绍SQLite的具体使用,这一篇重点介绍一下如何打开。 定义全局数据库访问句柄 /// 全局数据库访问句柄 private var db: COpaquePointer nil实现打开数据库函数 …

MVC中获取模型属性的Range和StringLength验证特性设置
MVC中的客户端及服务端模型验证信息都以ModelMetadata类型作为承载,在获得属性的ModelMetadata之后(还不知道怎么获取ModelMetadata的童鞋请自行恶补),我们可以轻松得到一些我们在模型中定义的特性,比如显示名称、是否…

以安装PyTorch为例说明Anaconda在Windows/Linux上的使用
在Windows10上配置完MXNet 1.3.0后,再配置PyTorch 1.0时,发现两者需要依赖的NumPy版本不一致,之前是通过pip安装NumPy,根据pip的版本不同,会安装不同版本的NumPy,使用起来很不方便,而且MXNet和P…

常用 SQL介绍
创建表 /*创建数据表CREATE TABLE 表名 (字段名 类型(INTEGER, REAL, TEXT, BLOB)NOT NULL 不允许为空PRIMARY KEY 主键AUTOINCREMENT 自增长,字段名2 类型,...)注意:在开发中,如果是从 Navicat 粘贴的 SQL,需要自己添加一个指令IF NO…

AttoNets,一种新型的更快、更高效边缘计算神经网络
作者 | Alexander Wong, Zhong Qiu Lin, and Brendan Chwyl 译者 | Rachel 出品 | AI科技大本营(ID:rgznai100)尽管机器学习已经在很多复杂的任务中取得了进展,但现有模型仍然面临许多边缘计算实践的困难,这些边缘计算场景包括移…

Appro DM8127 IPNC 挂载NFS遇到的问题及解决
对于Appro DM8127 IPNC,默认的启动方式是NAND is used for booting kernel and NAND is used as root filesystem 为了调试应用程序方便,通常使用挂载NFS作为 root filesystem 但是如果直接采用ti文档中所给的方法修改文件系统挂载方式(将启动…

提高C++性能的编程技术笔记:设计优化/可扩展性/系统体系结构相关+测试代码
1. 设计优化 我们可以粗略地将性能优化分为两种类型:编码优化和设计优化。编码优化定义为不需要完整理解要解决的问题或者应用程序的执行流程就能实施的优化。通过定义看出,编码优化用于局部代码,同时该过程不牵涉周围的代码。除了这些容易实…

ICLR 2020被爆半数审稿人无相关领域经验,同行评审制度在垮塌?
作者 | 若名出品 | AI科技大本营(ID:rgznai100)根据维基百科,同行评议(peer review),是指由一个或多个具有与作品生产者具有相似能力的人员(同行)对作品进行的评估活动。同行评审方法用于维持质…

Swift 中使用 SQLite——批量更新(事务处理)
本文是Swift 中使用 SQLite系列的收官之作,介绍一下在数据库中的批量更新。 事务 在准备做大规模数据操作前,首先开启一个事务,保存操作前的数据库的状态开始数据操作如果数据操作成功,提交事务,让数据库更新到数据操…

网络管理常用命令之二 - Ipconfig 命令详解(图文)
2、Ipconfig 命令...不带参数.../all 参数.../release 和 /realease6 参数.../Renew 和 /Renew6 参数.../flushdns 参数.../displaydns 参数2、Ipconfig 命令 ipconfig命令也是使用率非常高的一个命令,可用于显示系统的TCP/IP网络配置值,并刷新动态主…

Swift 中使用 SQLite——查询数据
本文主要介绍如何查询 SQLite 结果集,以及封装 SQLite 的操作方法。 准备测试代码 /// 从数据库中加载 person 数组 class func persons() -> [Person]? {// 1. 准备 SQLlet sql "SELECT id, name, age, height FROM T_Person;"// 2. 访问数据库// …

提高C++性能的编程技术笔记:总结
《提高C性能的编程技术》这本书是2011年出版的,书中有些内容的介绍可能已经过时,已不再适用于现在的C编程中,但大部分内容还是很有参考意义的。 这里是基于之前所有笔记的简单总结,笔记列表如下: 跟踪实例࿱…

13岁小孩都跟我抢Python了,完了!
以下来自一位程序员母亲和工作人员的对话。程序员妈妈:您好,可以帮我推荐一本适合我家小孩看的编程书籍吗?兔子:可以的呀,《Scratch从入门到精通》,这本书适合小孩学习,您可以先看一下哦~程序员…

Windows Mobile 6.0 SDK和中文模拟器下载
【转】 Windows Mobile 6.0 SDK和中文模拟器下载 Windows Mobile 6.5 模拟器2010年12月06日 星期一 07:48转载自 zhangyanle86终于编辑 zhangyanle86Windows Mobile 6.0 SDK和中文模拟器下载 SDK 6.0下载页面:http://www.microsoft.com/downloads/details.aspx?fam…

wxPython:Python首选的GUI库 | CSDN博文精选
作者 | 天元浪子来源 | CSDN博客文章目录概述窗口程序的基本框架事件和事件驱动菜单栏/工具栏/状态栏动态布局AUI布局DC绘图定时器和线程后记概述跨平台的GUI工具库,较为有名的当属GTK、Qt 和 wxWidgets 了。GTK是C实现的,由于C语言本身不支持OOP&#x…

Swift 中使用 SQLite——修改和删除数据
本文主要介绍在SQLite中修改数据、删除数据: 更新记录 /// 将当前对象信息更新到数据库 /// /// - returns: 是否成功 func updatePerson() -> Bool {guard let name name else {print("姓名不能为空")return false}if id < 0 {print("id 不…

用python3实现指定目录下文件sha256及文件大小统计
有时会统计某个目录下有哪些文件,每个文件的sha256及文件大小等相关信息,这里用python3写了个脚本用来实现此功能,此脚本可跨平台,同时支持windows和linux,脚本(get_dir_file_info.py)内容如下: import os…

Swift 中使用 SQLite——新增数据
本文重点介绍两个方面,1、新增数据,2、获取自动增长 ID。 建立 Person.swift 数据模型 /// 个人模型 class Person: NSObject {// MARK: - 模型属性/// 代号var id: Int64 0/// 姓名var name: String?/// 年龄var age 0/// 身高var height: Double …

投稿2877篇,EMNLP 2019公布4篇最佳论文
整理 | AI科技大本营(ID:rgznai100)近日,自然语言处理领域的顶级会议之一EMNLP 2019公布了年度最佳论文。EMNLP是由国际语言学会(ACL)下属的SIGDAT小组主办的自然语言处理领域的顶级国际会议,是自然语言算法…

对象检测工具包mmdetection简介、安装及测试代码
mmdetection是商汤和港中文大学联合开源的基于PyTorch的对象检测工具包,属于香港中文大学多媒体实验室open-mmlab项目的一部分。该工具包提供了已公开发表的多种流行的检测组件,通过这些组件的组合可以迅速搭建出各种检测框架。 mmdetection主要特性&am…

(转)eclipse 代码自动补全
转自:http://blog.csdn.net/yushuwai2010/article/details/11856129 一般默认情况下,Eclipse的代码提示功能是比MicrosoftVisualStudio的差很多的,主要是Eclipse本身有很多选项是默认关闭的,要开发者自己去手动配置。如果开发者不…

swift 多线程GCD和延时调用
GCD 是一种非常方便的使用多线程的方式。通过使用 GCD,我们可以在确保尽量简单的语法的前提下进行灵活的多线程编程。在 “复杂必死” 的多线程编程中,保持简单就是避免错误的金科玉律。好消息是在 Swift 中是可以无缝使用 GCD 的 API 的,而且…