QT——串口调试助手

news2024/11/5 21:49:59

目录

1.QSerialPort类包含了很多有关串口的API

2.实现串口的打开

2.1 方法一:通过函数实现

2.2 方法二:在ui界面右下角实现

3. 实现定时发送

3.1类的私有成员中添加定时器QTimer timer并去构造函数中初始化它

3.2帮助文档中有QTimer类相关的说明

3.3去连接该超时信号与槽函数

4.俩种方式实现时间显示

4.1通过线程实现

4.2 通过定时器实现时间显示

5. 实现发送与接收

6.实现Hex显示——实现每俩个字节加一个空格显示

7.文本框追加内容时注意事项

8.重写QComboBox组件的事件 —— 实现串口号的刷新

9.实现多文本发送

10.循环发送

第一种方法:不能通过延时函数处理,此方法为错误案例

第二种方法:定时器

第三种方法:多线程

11.Qt打包程序

1.首先切换为release,然后重新构建,并且运行

2.拷贝库文件

3.手动拷贝缺失库文件

4.整体进行压缩


1.QSerialPort类包含了很多有关串口的API

静态公有成员中提供了availablePorts() 函数去获取我当前电脑中存在的所有串口,存放在容器中元素类型是QSerialPortInfo

    // 获取当前系统中存在的串口
    QList<QSerialPortInfo> serialList = QSerialPortInfo::availablePorts();

    // 使用 qDebug 输出串口信息
    for (QSerialPortInfo serialinfo : serialList) {
        qDebug() << "Port Name:" << serialinfo.portName()            //端口名称
                 << ", Description:" << serialinfo.description()     //描述
                 << ", Manufacturer:" << serialinfo.manufacturer()   //制造商
                 << ", Serial Number:" << serialinfo.serialNumber(); //序列号
                 
		     ui->comboBox_01->addItem(serialinfo.portName());            //向combox组件中添加端口名称
    }

2.实现串口的打开

想要实现打开串口/关闭串口按键的点击反转,需要绑定槽函数中信号是clicked(bool checked),而不是普通的clicked()信号, 并且需要使得该按键状态是可以检测的,这里有俩种方法

2.1 方法一:通过函数实现

ui->btn_CloseOrOpenSerial->setCheckable(true);

2.2 方法二:在ui界面右下角实现

3. 实现定时发送

3.1类的私有成员中添加定时器QTimer timer并去构造函数中初始化它

3.2帮助文档中有QTimer类相关的说明

  • 设置定时器间隔时间 void setInterval(int time);
  • Signals中包含信号检测是否超时 void timeout();

3.3去连接该超时信号与槽函数

  • 在超时信号的槽函数里面进行数据的发送

4.俩种方式实现时间显示

4.1通过线程实现

curtimeupdate.h

#ifndef CURTIMEUPDATE_H
#define CURTIMEUPDATE_H

#include <QDateTime>
#include <QThread>
#include <QObject>

class curTimeUpdate : public QThread {
    Q_OBJECT

public:
    explicit curTimeUpdate(QObject *parent = nullptr): QThread(parent){};

signals:
    void updateTime(const QString &timeString);

protected:
    // 每间隔1s发送一次时间信号
    void run() override{
        while(1){
            // 获取当前时间
            QDateTime dataTime = QDateTime::currentDateTime();
            QDate date = dataTime.date();
            int year = date.year();
            int month = date.month();
            int day = date.day();
            QTime time = dataTime.time();
            int hour = time.hour();
            int minute = time.minute();
            int second = time.second();

            // 将时间拼装起来,确保月份和日期、小时、分钟、秒钟都是双位数
            QString currentTime = QString("%1-%2-%3 %4:%5:%6")
                .arg(year)
                .arg(month, 2, 10, QChar('0'))  // 确保月是两位数
                .arg(day, 2, 10, QChar('0'))    // 确保日是两位数
                .arg(hour, 2, 10, QChar('0'))   // 确保小时是两位数
                .arg(minute, 2, 10, QChar('0')) // 确保分钟是两位数
                .arg(second, 2, 10, QChar('0')); // 确保秒钟是两位数

            //发送信号
            emit updateTime(currentTime);
            sleep(1);

        }
    }

};

#endif // CURTIMEUPDATE_H

widget.cpp

// 创建线程更新右下角时间
    timeUpdater = new curTimeUpdate;
    connect(timeUpdater, &curTimeUpdate::updateTime, this, &Widget::updateTimeLabel);
    timeUpdater->start();   // 启动线程
void Widget::updateTimeLabel(const QString &timeString) {
    ui->label_nowTime->setText(timeString); // 更新标签显示时间
}

4.2 通过定时器实现时间显示

实现逻辑:定时器定时1s,每当定时器超时,会自动发出超时信号,检测到该信号时,调用槽函数实现当前时间的获取

widget.h中添加以下内容

Private:
	QTimer* getSysTimeTimer;
private slots:
	void getSysTime();

widget.cpp

  	getSysTimeTimer = new QTimer(this);
    getSysTimeTimer->setInterval(1000);                                                    //设置定时器2的间隔时间(毫秒)
    connect(getSysTimeTimer, &QTimer::timeout, this, &Widget::getSysTime);                 //定时器2超时
    getSysTimeTimer->start();                                                              //启动定时器2

// 定时器超时槽函数
void Widget::getSysTime()
{
    // 获取当前时间
    QDateTime dataTime = QDateTime::currentDateTime();
    QDate date = dataTime.date();
    QTime time = dataTime.time();

    // 提取年、月、日、时、分、秒
    int year   = date.year();
    int month  = date.month();
    int day    = date.day();
    int hour   = time.hour();
    int minute = time.minute();
    int second = time.second();

    // 将时间拼装起来,确保月份和日期、小时、分钟、秒钟都是双位数
    QString currentTime = QString("%1-%2-%3 %4:%5:%6")
        .arg(year)
        .arg(month, 2, 10, QChar('0'))  // 确保月是两位数
        .arg(day, 2, 10, QChar('0'))    // 确保日是两位数
        .arg(hour, 2, 10, QChar('0'))   // 确保小时是两位数
        .arg(minute, 2, 10, QChar('0')) // 确保分钟是两位数
        .arg(second, 2, 10, QChar('0')); // 确保秒钟是两位数

    // 更新标签显示时间
    ui->label_nowTime->setText(currentTime);
}

5. 实现发送与接收

// 发送按键槽函数
void Widget::on_pushButton_19_clicked()
{
    int WriteCnt = 0;
    QString sendData = ui->lineEdit_4->text();
    //Hex发送是否勾选,此处为勾选
    if(ui->checkBox_15->isChecked()){
        QByteArray tmpArray = ui->lineEdit_4->text().toLocal8Bit();
        //检查字节数是否是偶数
        if(tmpArray.size() % 2 != 0){
            ui->label_5->setText("input error!");
            return;
        }
        //检查是否符合16进制表达
        for(char c:tmpArray){
            if(!std::isxdigit(c)){
                ui->label_5->setText("input error!");
                return;
            }
        }

        //检查是否添加新行
        if(ui->checkBox_14->isChecked()){
            tmpArray = tmpArray.append("\\r\\n");
        }
        //转化为16进制发送
        QByteArray tmp = QByteArray::fromHex(tmpArray);

        WriteCnt = serialPort->write(tmp);

    }else{
        QByteArray data = sendData.toLocal8Bit();
        //检查是否添加新行
        if(ui->checkBox_14->isChecked()){
            data = data.append("\\r\\n");
        }
        WriteCnt = serialPort->write(data);
    }

    if(WriteCnt == -1){
        ui->label_5->setText("Send false!");
    }else{
        ui->label_5->setText("Send Ok!");
        ui->label_4->setText("Send: " + QString::number(WriteCntTotal));

        if(0 != strcmp(sendBak.toLocal8Bit().constData(), sendData.toLocal8Bit().constData())){
            ui->textEdit_Record->append(sendData);
            sendBak = sendData;
        }
    }

}
// 接受数据槽函数
void Widget::on_SerialData_reched()
{
    QString revData = serialPort->readAll();                        // 读取所有可用的数据
    qDebug() << "接受到的新数据为:" << revData;
    if(revData != NULL){
        //a.是否勾选自动换行
        if(ui->checkBox_6->isChecked()) revData.append("\\r\\n");
        //b.更新接受长度
        RevCntTotal += revData.size();                              // 统计接受到的字节数
        ui->label_7->setText("Rev OK!");
        ui->label_3->setText("Rev: " + QString::number(RevCntTotal));

        //c.检查hex显示是否勾选
        if(ui->checkBox_5->isChecked()){
            //将新数据转化为Hex
            QByteArray tmp = revData.toUtf8();
            qDebug() << "tmp:" <<tmp;
            QByteArray tmpHexString = revData.toUtf8().toHex().toUpper();
            qDebug() << "转化后的新数据为:" << tmpHexString;
            //获取旧数据
            QString tmpStringHex = ui->textEdit_Rev->toPlainText(); //因为勾选了,读出来的就是hex
            //拼接旧数据与新数据
            tmpHexString = tmpStringHex.toUtf8() + tmpHexString;
            //重新显示在控件上
            ui->textEdit_Rev->setText(tmpHexString);

        }else{
            //接受时间是否勾选,此处为未勾选
            if(ui->checkBox_4->checkState()== Qt::Unchecked){
                ui->textEdit_Rev->insertPlainText(revData);
            }else{
                getSysTime();
                ui->textEdit_Rev->insertPlainText("【"+currentTime+"】 "+revData);
            }
        }
    }
}

6.实现Hex显示——实现每俩个字节加一个空格显示

QString 类中,mid() 函数用于提取字符串的子字符串。

QString mid(int position, int length);
//position: 指定从哪个位置开始提取子字符串
//length: 指定要提取的字符数。如果这个参数省略,则默认提取到字符串的末尾。
// Hex显示槽函数
void Widget::on_checkBox_5_clicked(bool checked)
{
    if (checked) {
        // 获取原始文本 QString  \\x01\\x02\\x03
        QString revDisplay = ui->textEdit_Rev->toPlainText();

        // 转换为      QByteArray \\x01\\x02\\x03
        QByteArray byteArray = revDisplay.toUtf8();
        // 转换为      QByteArray  010203
        byteArray = byteArray.toHex();             

        QString lastShow;
        // 转换为      QString     010203
        revDisplay = QString::fromUtf8(byteArray); 
        for(int i=0; i<revDisplay.size();i+=2){
            lastShow += revDisplay.mid(i,2) + " ";
        }
        // 显示添加空格后的16进制内容
        ui->textEdit_Rev->setText(lastShow);
    } else {
        // 获取 Hex 文本
        QString hexDisplay = ui->textEdit_Rev->toPlainText();

        // 将 Hex 转换回原始字符串
        //QByteArray \\x01\\x02\\x03
        QByteArray byteArray = QByteArray::fromHex(hexDisplay.toUtf8());
        //QString  \\x01\\x02\\x03
        QString normalDisplay = QString::fromUtf8(byteArray);

        // 设置文本为正常字符串
        ui->textEdit_Rev->setText(normalDisplay);
    }
}

7.文本框追加内容时注意事项

我们使用的函数是insertPlainText()而不是append()。因为append()函数添加为内容后会自动换行。

8.重写QComboBox组件的事件 —— 实现串口号的刷新

  • 当鼠标按下QComboBox组件时,发送reflesh()刷新信号。
  • 在widget.cpp中连接该reflesh()信号与槽函数,槽函数中实现串口号的检测刷新。

mycombobox.h

#ifndef MYCOMBOBOX_H
#define MYCOMBOBOX_H

#include <QComboBox>

class myCombobox : public QComboBox
{
    Q_OBJECT
public:
    myCombobox(QWidget *parent);
protected:
    void mousePressEvent(QMouseEvent *e) override;  //鼠标按下事件

signals:
    void reflesh();  //刷新信号
};

#endif // MYCOMBOBOX_H

mycombobox.cpp

#include "mycombobox.h"

#include <QMouseEvent>

myCombobox::myCombobox(QWidget *parent):QComboBox(parent)
{}

void myCombobox::mousePressEvent(QMouseEvent *e)
{
    if(e->button() == Qt::LeftButton){
        emit reflesh();
    }

    QComboBox::mousePressEvent(e);
}

9.实现多文本发送

构造函数中先生成按键的名称,然后查找系统中是否有该名字的按键,有的话指针指向它,接着给该按键绑定槽函数

for(int i = 1; i <= 8; i++){
        QString btnName = QString("pushButton_%1").arg(i);                        //生成按键名字
        QPushButton* btn = findChild<QPushButton *>(btnName);                     //查找组件中是否有该名字的按键,若有,将指针指向该按键
        if(btn){
            btn->setProperty("buttonId",i);                                       //给该按键添加属性
            buttons.append(btn);                                                  //将该按键添加到容器中
            connect(btn,SIGNAL(clicked()),this,SLOT(on_command_button_clicked()));//给该按键连接信号与槽函数
        }

        QString lineEditName = QString("lineEdit_%1").arg(i);                     //生成输入框名字
        QLineEdit *lineEdit = findChild<QLineEdit *>(lineEditName);               //查找组件中是否有该名字的输入框,若有,将指针指向该输入框
        lineEdits.append(lineEdit);                                               //将该输入框添加到容器中

        QString checkBoxName = QString("checkBox_%1").arg(i);                     //生成checkboBox名字
        QCheckBox *checkBox = findChild<QCheckBox *>(checkBoxName);               //查找组件中是否有该名字的checkboBox,若有,将指针指向该checkboBox
        checkBoxs.append(checkBox);                                               //将该checkboBox添加到容器中

    }

槽函数中先通过sender()函数获取到发送信号的对象,接着获取按键的属性,接着根据属性生成对应的名称

void Widget::on_command_button_clicked() {
    // 通过 sender() 函数获取发出信号的对象,在通过 qobject_cast<> 方法进行类型转换
    QPushButton *btn = qobject_cast<QPushButton *>(sender());
    if (btn) {
        // 获取按键的属性 buttonId 的值,并转换为整数
        int num = btn->property("buttonId").toInt();

        // 根据 buttonId 构造与之对应的 QLineEdit 对象的名称
        QString lineEditName = QString("lineEdit_%1").arg(num);
        QLineEdit *lineEdit = findChild<QLineEdit *>(lineEditName);
        if (lineEdit) {
            if (lineEdit->text().isEmpty()) {
                return; // 如果文本为空,直接返回,不发送
            }
            ui->lineEdit_sendData->setText(lineEdit->text());
        }

        // 根据 buttonId 构造与之对应的 QCheckBox 对象的名称
        QString hexName = QString("checkBox_%1").arg(num);
        QCheckBox *checkBox = findChild<QCheckBox *>(hexName);
        ui->checkBox_sendHex->setChecked(checkBox ? checkBox->isChecked() : false); // 确保 checkBox 存在后再获取状态

        // 只有在 lineEdit 有内容的情况下发送数据
        on_pushButton_send_clicked();
    }
}

10.循环发送

第一种方法:不能通过延时函数处理,此方法为错误案例

//循环发送()
void Widget::on_checkBox_cirSend_clicked(bool checked)
{
    if(checked){
        for(QPushButton *btn : buttons){
            //当前按键发送点金信号
            emit btn->clicked();
            QThread::msleep(ui->spinBox->text().toInt());
        }
    }
}

第二种方法:定时器

实现逻辑:当勾选循环发送时候,调用槽函数:去设置定时器的间隔时间,并且启动定时器。当定时器超时时候,执行槽函数去发送信号。

void Widget::on_checkBox_cirSend_clicked(bool checked)
{
    if(checked){
        timer3->setInterval(ui->spinBox->text().toInt());
        timer3->start(); // 启动定时器
    }else{
        timer3->stop();
    }
}

void Widget::buttons_handler()
{
    if(btnIndex < 8){
        QPushButton *btn = buttons[btnIndex];
        emit btn->click();
        btnIndex++;
    }else{
        btnIndex = 0;
    }
}

第三种方法:多线程

缺点,没办法与ui组件关联,无法通过ui组件获取定时时间。

11.Qt打包程序

11.1.首先切换为release,然后重新构建,并且运行

11.2.拷贝库文件

首先进入C盘

C:

进入你程序的目录下

 cd C:\\Users\\mi\\Desktop\\Qt Project\\build-untitled-Desktop_Qt_5_12_9_MinGW_64_bit-Release\\release

执行命令,拷贝库到该目录下

D:\\Linux\\Qt\\5.12.9\\mingw73_32\\bin\\windeployqt.exe untitled.exe

11.3.手动拷贝缺失库文件

11.4.整体进行压缩即可

12.整体代码如下

tunnek/QT- (github.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2231053.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

全自动一键批量创建站群网站插件 | Z-BlogPHP 堆词起站工具

在当今竞争激烈的数字营销世界&#xff0c;如何快速提升网站曝光率和流量&#xff1f;答案就是智能站群系统。 本文将结合实际效果&#xff0c;介绍一款功能强大的站群系统&#xff0c;重点讲述其堆词功能、泛目录管理、一键批量创建、内容转码、自定义标签和GPT内容生成与发布…

计算机毕业设计Spark+大模型知识图谱中药推荐系统 中药数据分析可视化大屏 中药爬虫 机器学习 中药预测系统 中药情感分析 大数据毕业设计

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

Linux云计算 |【第五阶段】CLOUD-DAY7

主要内容&#xff1a; 在kubernetes平台上理解掌握各种控制器的用法&#xff1a;掌握kubectl管理命令、掌握POD原理、掌握集群调度的规则、熟悉控制器资源文件&#xff1b; 一、kubectl 常用命令 Kubectl是用于控制Kubernetes集群的命令行工具&#xff1b; - 格式&#xff1…

json-server的使用(根据json数据一键生成接口)

一.使用目的 在前端开发初期&#xff0c;后端 API 可能还未完成&#xff0c;json-server 可以快速创建模拟的 RESTful API&#xff0c;帮助前端开发者进行开发和测试。 二.安装 npm install json-server //局部安装npm i json-server -g //全局安装 三.使用教程 1.准备一…

在VS中安装chatGPT

2、在VSCode中打开插件窗口 3、输入ChatGPT 4、这里有个ChatGPT中文版&#xff0c;就它了 5、安装 6、这时候侧边栏多了一个chatGPT分页图标&#xff0c;点击它 7、打个招呼 8、好像不行 9、看一下细节描述 10、根据要求按下按下快捷键 Ctrl Shift P 11、切换成国内模式 12、…

# linux从入门到精通-从基础学起,逐步提升,探索linux奥秘(十九)--mysql数据库基本操作

linux从入门到精通-从基础学起&#xff0c;逐步提升&#xff0c;探索linux奥秘&#xff08;十九&#xff09;–mysql数据库基本操作 一、MySQL的基本操作&#xff08;1&#xff09;&#xff08;难点&#xff09; 1、名词介绍 以Excel文件举例&#xff1a; 数据库&#xff1a…

冒泡排序,快速排序讲义

冒泡排序 基本原理&#xff1a;对存放原始数据的数组&#xff0c;按从前往后的方向进行多次扫描&#xff0c;每次扫描称为一趟。当发现相邻的两个数据次序和排序要求的大小次序不符合的时候&#xff0c;即将这两个数据进行互换。如果从小到大排序&#xff0c;这时&#xff0c;…

智能语音助手:开启智能交互的新时代

随着人工智能和自然语言处理技术的进步&#xff0c;智能语音助手已经逐渐成为日常生活中的一部分。无论是手机上的虚拟助手、智能音箱&#xff0c;还是车载导航和智能家居控制系统&#xff0c;智能语音助手的应用越来越广泛&#xff0c;为用户提供了高效便捷的交互体验。通过语…

vue data变量之间相互赋值或进行数据联动

摘要&#xff1a; 使用vue时开发会用到data中是数据是相互驱动&#xff0c;经常会想到watch,computed&#xff0c;总结一下&#xff01; 直接赋值&#xff1a; 在 data 函数中定义的变量可以直接在方法中进行赋值。 export default {data() {return {a: 1,b: 2};},methods: {u…

uniapp ,微信小程序,滚动(下滑,上拉)到底部加载下一页内容

前言 小程序的内容基本都是滑动到底部加载下一页&#xff0c;这个一般都没有什么好用的组件来用&#xff0c;我看vant和uniapp的插件里最多只有个分页&#xff0c;没有滚动到底部加载下一页。再次做个记录。 效果预览 下滑到底部若是有下一页&#xff0c;则会自动加载下一页&…

【数据分享】2024年我国省市县三级的休闲娱乐设施数量(免费获取/18类设施/Excel/Shp格式)

KTV、棋牌室、音乐厅等休闲服务设施的配置情况是一个城市公共基础设施完善程度的重要体现&#xff0c;一个城市休闲服务设施种类越丰富&#xff0c;数量越多&#xff0c;通常能表示这个城市的公共服务水平越高&#xff01; 本次我们为大家带来的是我国各省份、各地级市、各区县…

Flarum:简洁而强大的开源论坛软件

Flarum简介 Flarum是一款开源论坛软件&#xff0c;以其简洁、快速和易用性而闻名。它继承了esoTalk和FluxBB的优良传统&#xff0c;旨在提供一个不复杂、不臃肿的论坛体验。Flarum的核心优势在于&#xff1a; 快速、简单&#xff1a; Flarum使用PHP构建&#xff0c;易于部署&…

【CSS in Depth 2 精译_056】8.4 CSS 的新特性——原生嵌套(Nesting)+ 8.5 本章小结

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 【第三部分 现代 CSS 代码组织】 ✔️【第八章 层叠图层及其嵌套】 ✔️ 8.1 用 layer 图层来操控层叠规则&#xff08;上篇&#xff09; 8.1.1 图层的定义&#xff08;上篇&#xff09;8.1.2 图层的…

Qt字符编码

目前字符编码有以下几种&#xff1a; 1、UTF-8 UTF-8编码是Unicode字符集的一种编码方式(CEF)&#xff0c;其特点是使用变长字节数(即变长码元序列、变宽码元序列)来编码。一般是1到4个字节&#xff0c;当然&#xff0c;也可以更长。 2、UTF-16 UTF-16是Unicode字符编码五层次…

分布式事务-SpringBoot集成Seata

1.本地事务和分布式事务概念 事务四大特性 原子性&#xff1a;事务不可再分一致性&#xff1a;数据改变前后&#xff0c;总量必须一致隔离性&#xff1a;事务之间相互隔离&#xff0c;互不干扰持久性&#xff1a;事务一旦提交&#xff0c;数据就会持久化到磁盘&#xff0c;不…

win10 wsl2 install

安装 迁移 docker WSL2常用指令 在 WSL2 中推出或关闭 WSL 实例&#xff0c;可以使用以下几种方法&#xff1a; 1. 使用 exit 命令 在 WSL2 终端中&#xff0c;输入以下命令即可退出当前的 WSL 会话&#xff1a; exit2. 使用 logout 命令 你也可以使用&#xff1a; l…

「Mac畅玩鸿蒙与硬件23」鸿蒙UI组件篇13 - 自定义组件的创建与使用

自定义组件可以帮助开发者实现复用性强、逻辑清晰的界面模块。通过自定义组件,鸿蒙应用能够提高代码的可维护性,并简化复杂布局的构建。本篇将介绍如何创建自定义组件,如何向组件传递数据,以及如何在不同页面间复用这些组件。 关键词 自定义组件复用组件属性传递组件通信组…

flutter 专题二 Flutter状态管理之Riverpod 0.8.4

一 、flutter 有哪些状态管理方式 Flutter的状态管理方式有很多&#xff0c;Redux、 Bloc、 MobX、Provider等等。单单一个Provider&#xff0c;我也见到了各种组合&#xff0c;例如ChangeNotifier Provider / StateNotifier Provider&#xff08; freezed&#xff09;。各…

uniapp编译多端项目App、小程序,input框键盘输入后

项目场景&#xff1a; uniapp编译后的小程序端&#xff0c;app端 在一个输入框 输入消息后&#xff0c;点击键盘上的操作按钮之后键盘不被收起&#xff0c;点击其他发送按钮时&#xff0c;键盘也不被收起。 问题描述 在编译后的app上普通的事件绑定&#xff0c;tap,click在发…

高并发编程

一台64G内存的服务器QPS可以达到9W&#xff0c;TPS&#xff08;事务&#xff09;可以达到5K&#xff0c;每个TPS大约包含18个QPS.只读的话QPS可以达到30~40万.阿里云有相关测试工具、测试方法、测试结果。 1、volatile 保证可见性&#xff0c;禁止指令重排&#xff0c;避免多线…