32位和64位区别

范彬

链接:https://www.zhihu.com/question/23408154/answer/24499675

64bit软件和32bit软件最大的区别是64bit的软件可以同时操作大于4GB的内存。注意这里的内存指的是地址空间,而不是物理内存。比如现在有一个10GB的数据库需要进行排序。64bit的软件可以malloc一个10GB的空间把整个数据库“放进”内存然后使用任意经典排序算法,而32bit的软件在malloc时就会崩溃(out-of-memory)。所以32位软件的程序员只能使用复杂的算法显式的分块读入,局部排序,写回数据库,然后重复。这样不仅程序复杂难写,程序员swap内存和文件的算法效率可能也不如OS自动处理来的高效。

另一方面,64bit软件巨大的内存空间也可能加速物理内存的消耗,增加寻址的开销,因此未必总是能够提高性能。

当然最终系统的效率还是取决于物理内存的大小,64bit只是解决了地址空间的瓶颈。

补佳林的回答

64 位软件和 32 位有什么具体区别? - 补佳林的回答 - 知乎 https://www.zhihu.com/question/23408154/answer/24537270

我来说个不好的地方,64位下指针变成8字节,很多c结构体占用空间加大,相当于cpu的缓存变小了。

gggxxx

链接:https://www.zhihu.com/question/23408154/answer/24527239

除了内存访问更重要的还有64位指令集运算。理论上64位运算强于32位运算,但是这依赖于代码优化。

对普通用户来说有2点。

  1. 现在主流的比较新的桌面操作系统都是同时兼容64位程序和32位程序,包括ios也是同时兼容32位和64位。也就是说,用户不管安装32位还是64位程序都没有问题。

  2. 软件编译成64位后并不一定比32位程序运行速度快,很多时候64位程序都慢于32位程序。事实上很多开发者把程序从32位转化成64位,只是做兼容64位而已,根本没有针对64位特性做优化。

很多流行软件的32位版本其实更加稳定和速度快。

匿名用户

链接:https://www.zhihu.com/question/23408154/answer/30793420

多少位是指cpu的寄存器宽度不同,比如16位通用寄存器有一个叫ax,这意味着ax寄存器能存储16bit数据, 在32位中这个寄存器是eax,能存储32bit数据。64位中叫rax。

寻址能力是指cpu寻址总线的宽度。比如16位的x86的u寻址能力是20位,因为寄存器只有16位,所以用seg x16 + offset的方式表示,这就是教科书上所说的逻辑地址。实际上逻辑地址可能产生21位的地址,但是因为寻址总线的宽度只有20所以溢出的一位都会被抛弃。在计算机开机的过程中,bootloader就会读写keyboard controller的60和64端口判断是否开启大于20位的寻址模式。

周全

64 位软件和 32 位有什么具体区别? - 周全的回答 - 知乎 https://www.zhihu.com/question/23408154/answer/24542634

1、对os来说,64位和32位指虚拟地址空间,32位最大4GB,64位理论上16TB,且目前有16TB的

2、对硬件来说,64位和32位指数据宽度,64位一次取8字节,32取4字节

3、对应用程序来说,指使用的指令宽度,基于OS和硬件

MySQL数据库连接池

内容

C++实现的小型项目, MySQL数据库连接池, 属于常用组件;

约400到500行代码, 代码不多, 麻雀虽小, 五脏俱全:

  1. 涉及到数据库编程;
  2. 单例模式
  3. queue队列容器
  4. C++11多线程编程, 线程互斥, 线程同步通信, unique_lock
  5. 基于CAS的原子类型
  6. 智能指针shared_ptr
  7. lambda表达式
  8. 生产者-消费者线程模型

项目背景

为了提高MySQL数据库(需要特别注意的, 它是基于C/S设计的)的访问瓶颈,除了在服务器端增加缓存服务器缓存常用的数据之外(例如Redis),还可以增加连接池,来提高MySQL Server的访问效率,在高并发情况下,大量的TCP三次握手、MySQL Server连接认证、MySQL Server关闭连接回收资源和TCP四次挥手所耗费的性能时间也是很明显的,增加连接池就是为了减少这一部分的性能损耗。

在市场上比较流行的连接池包括阿里的druid,c3p0以及apache dbcp连接池,它们对于短时间内大量的数据库增删改查操作性能的提升是很明显的,但是它们全部由Java实现。那么本项目就是为了在C/C++语言下,提供MySQL Server的访问效率,实现基于C++代码的数据库连接池模块。

连接池功能介绍

该项目是基于C++语言实现的连接池,主要实现若干个通用基础功能。

连接池一般包含了数据库连接所用的ip地址、port端口号、用户名和密码以及其它的性能参数,例如初
始连接量,最大连接量,最大空闲时间、连接超时时间等;

  1. 初始连接量(initSize)
    1. 表示连接池事先会和MySQL Server创建initSize个数的connection连接;
    2. 当应用发起MySQL访问时,不用再创建和MySQL Server新的连接,直接从连接池中获取一个可用的连接就可以;
    3. 使用完成后,并不去释放connection,而是把当前connection再归还到连接池当中。
  2. 最大连接量(maxSize)
    1. 总的连接数量上限是maxSize;
    2. 当并发访问MySQL Server的请求增多时,初始连接量已经不够使用了,此时会根据新的请求数量去创建更多的连接给应用去使用;
    3. 但是,不能无限制的创建连接,因为每一个连接都会占用一个socket资源,一般连接池和服务器程序是部署在一台主机上的,如果连接池占用过多的socket资源,那么服务器就不能接收太多的客户端请求了;
    4. 当这些连接使用完成后,再次归还到连接池当中来维护。
  3. 最大空闲时间(maxIdleTime)
    1. 当访问MySQL的并发请求多了以后,连接池里面的连接数量会动态增加,上限是maxSize个;
    2. 当这些连接用完再次归还到连接池当中;
    3. 如果在指定的maxIdleTime里面,这些新增加的连接都没有被再次使用过,那么新增加的这些连接资源就要被回收掉,只需要保持初始连接量initSize个连接就可以了。
  4. 连接超时时间(connectionTimeout)
    1. 当MySQL的并发请求量过大,连接池中的连接数量已经到达maxSize了,而此时没有空闲的连接可供使用,那么此时应用从连接池获取连接需要通过阻塞的方式获取连接;
    2. 阻塞时间如果超过connectionTimeout时间,那么获取连接失败,无法访问数据库;

该项目主要实现上述的连接池四大功能,其余连接池更多的扩展功能,可以在该框架的基础上进行很好的拓展;

设计思路

  1. 需要抽象出两个类
    1. ConnectionPool - 连接池
    2. Connection - 封装数据库操作, 增删改查
  2. 连接池只需要一个实例, 则ConnectionPool设计为单例模式
  3. ConnectionPool需要提供获取MySQL连接Connection的接口
  4. 空闲连接Connection全部维护在一个Connection队列中, 使用互斥锁保证队列的线程安全
  5. 如果在获取连接时发现空闲连接队列空, 则需要动态创建新连接, 但是上限数量是maxSize, 在创建新连接的过程中, 消费者线程需要忙等待connectionTimeout时长, 直到队列中不空; 若时长一到仍获取未果则认定为连接失败; 可以使用带超时时间的mutex互斥锁来实现连接超时时间;
  6. 使用量下降后, 如果队列中的空闲连接保持空闲超过maxIdleTime, 需要释放连接, 直到减少到initSize个连接; 这个释放的过程需要放在独立线程做 - 定时线程, 清理队列多余的空闲连接;
  7. 用户获取的连接用shared_ptr智能指针来管理,用lambda表达式定制连接释放的功能(不真正释放连接,而是把连接归还到连接池中)
  8. 连接的生产和连接的消费采用生产者-消费者线程模型来设计,使用了线程间的同步通信机制条件变量和互斥锁;

MySQL数据库编程

公共代码

简易日志工具 - 向标准输出设备输出

1
2
3
4
5
6
#include<iostream>
#define LOG(str) \
do { \
std::cout << __FILE__ << ":" << __LINE__ << ":" \
<< __TIMESTAMP__ << ":" << str << std::endl; \
} while(0)

MySQLConnection - 封装MySQL数据库操作

成员变量

MYSQL *m_conn - 记录MYSQL类型的指针, 以获取这个mysql连接

1
2
private:
MYSQL *m_conn;

成员函数

  1. 构造/析构 - 初始化/释放数据库连接
1
2
3
4
5
public:
/* 初始化数据库连接 */
MySQLConnection();
/* 释放数据库连接资源 */
~MySQLConnection();
  1. getConnection - 获取连接, 即获取成员m_conn
1
2
3
public:
/* 获取连接 */
MYSQL * getConnection();
  1. connect - 连接数据库, 返回值为bool, 说明连接成功与否
1
2
3
4
public:
/* 连接数据库 */
bool connect(std::string ip, unsigned short port,
std::string user, std::string password, std::string dbname);
  1. query - 查询操作, 参数是string类型的sql语句, 返回值为MYSQL_RES, 即MySQL结果集类型
1
2
3
public:
/* 查询操作 */
MYSQL_RES * query(std::string sql);
  1. update - 更新操作, 参数是string类型的sql语句, 返回值为bool, 说明更新成功与否
1
2
3
public:
/* 更新操作 */
bool update(std::string sql);

代码实现

  1. 构造 - 调用mysql_init, 实际上只是对mysql连接进行空间资源的开辟, 返回一个指针赋给m_conn成员, 没有真正连接, 因此传入nullptr
1
2
3
4
5
/* 初始化数据库连接 */
MySQLConnection::MySQLConnection()
{
m_conn = mysql_init(nullptr);
}
  1. 析构 - 调用mysql_close(m_conn), 对MySQL连接资源进行释放
1
2
3
4
5
6
7
8
/* 释放数据库连接资源 */
MySQLConnection::~MySQLConnection()
{
if(m_conn != nullptr)
{
mysql_close(m_conn);
}
}
  1. connect - 连接数据库, 内部调用mysql_real_connect, 传入m_conn, 以及server ip地址, user号, 密码, 要连接的数据库name, 服务器端口;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* 连接数据库 */
bool MySQLConnection::connect(std::string ip, unsigned short port,
std::string user, std::string password,
std::string dbname)
{
MYSQL *p = mysql_real_connect(m_conn, ip.c_str(), user.c_str(),
password.c_str(), dbname.c_str(),
port, nullptr, 0);
if(p != nullptr)
{
/**
* C/C++代码默认的编码字符是ASCII,
* 如果不设置, 则从MySQL上拉下来的中文无法正常显示
*/
mysql_query(m_conn, "set name gbk");
LOG("connect mysql success!");
}
else
{
LOG("connect mysql failed!");
}
return p != nullptr;
}
  1. query - 查询操作
    1. 内部调用mysql_query, 传入m_conn, sql-string的C风格字符串首址;
      1. mysql_query的返回值:
        1. 如果查询成功,返回0;
        2. 如果出现错误,返回非0值。
    2. 返回值需要调用mysql_use_result(m_conn)获取结果集, 再return;
1
2
3
4
5
6
7
8
9
10
/* 查询操作 */
MYSQL_RES * MySQLConnection::query(std::string sql)
{
if(mysql_query(m_conn, sql.c_str()) == 0)
{
LOG("select failed: " + sql);
return nullptr;
}
return mysql_use_result(m_conn);
}
  1. update - 更新操作
    1. 内部调用mysql_query, 传入m_conn, sql-string的c风格字符串首址;
    2. 判断mysql_query的返回值, 若为非0则更新失败; 若为0则更新成功;
1
2
3
4
5
6
7
8
9
10
/* 更新操作 */
bool MySQLConnection::update(std::string sql)
{
if(mysql_query(m_conn, sql.c_str()) == 0)
{
LOG("update failed: " + sql);
return false;
}
return true;
}

连接池

MySQLConnectionPool

成员变量

成员函数

getConnection

1
2
3
4
5
/* 获取连接 */
MYSQL * MySQLConnection::getConnection()
{
return m_conn;
}

代码实现

压力测试

建个表

1
2
3
4
5
6
CREATE TABLE user(
id INT UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
age TINYINT NOT NULL,
sex ENUM('male', 'female') NOT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;