C++ 并发编程实战 第十一章 多线程应用的测试和除错
目录
11.1 与并发相关的错误类型
11.1.1 不必要的阻塞
11.1.2 条件竞争
11.2 定位并发错误的技术
11.2.1 代码审阅——发现潜在的错误
11.2.2 通过测试定位并发相关的错误
11.2.3 可测试性设计
11.2.4 多线程测试技术
11.2.5 构建多线程测试代码
11.2.6 测试多线程代码性能
参考《C++ 并发编程实战》 著:Anthony Williams 译: 吴天明
11.1 与并发相关的错误类型
有一些错误与使用并发直接相关,本章重点关注这些错误。通常,并发相关的错误通常有两大类:
不必要的阻塞
条件竞争
11.1.1 不必要的阻塞
这个主题可以分成以下几个问题:
死锁——如在第3章所见,死锁的情况下,两个线程会互相等待。当线程产生死锁,应该完成的任务就会持续搁置。举个例子来说,一些线程是负责对用户界面操作的线程,在死锁的情况下,用户界面就会无响应。另一些例子中,界面接口会保持响应,不过有些任务就无法完成,比如:查询无结果返回或文档未打印。
活锁——与死锁的情况类似。不同的地方在于线程不是阻塞等待,而是在循环中持续检查,例如:自旋锁。比较严重的情况下,其表现和死锁一样(应用不会做任何处理,停止响应),CPU的使用率还居高不下;因为线程还在循环中被检查,而不是阻塞等待。不太严重的情况下,因为使用随机调度,活锁的问题还是可以解决的。
I/O阻塞或外部输入——当线程被外部输入所阻塞,线程也就不能做其他事情了(即使,等待输入的情况永远不会发生)。因此,被外部输入所阻塞,就会让人不太高兴,因为可能有其他线程正在等待这个线程完成某些任务。
11.1.2 条件竞争
条件竞争经常会产生以下几种类型的错误:
数据竞争——因为未同步访问一块共享内存,将会导致代码产生未定义行为。第5章已经介绍了数据竞争,也了解了C++的内存模型。数据竞争通常发生在错误的使用原子操作上,做同步线程的时候,或没使用互斥量保护共享数据的时候。
破坏不变量——主要表现为悬空指针(因为其他线程已经将要访问的数据删除了),随机存储错误(因为局部更新,导致线程读取了不一样的数据),以及双重释放(比如:当两个线程对同一个队列同时执行pop操作,想要删除同一个关联数据),等等。不变量被破坏可以看作为“基于数据”的问题。当独立线程需要以一定顺序执行某些操作时,错误的同步会导致条件竞争,比如:顺序被破坏。
生命周期问题——虽然这类问题也能归结为破坏了不变量,不过这里将其作为一个单独的类别给出。这里的问题是线程会访问不存在的数据,这可能是因为数据被删除或销毁了,或者转移到其他对象中去了。生命周期问题,通常是在一个线程引用了局部变量,在线程还没有完成前,局部变量的“死期”就已经到了,不过这个问题并不止存在这种情况下。当手动调用join()等待线程完成工作,需要保证异常抛出的时候,join()还会等待其他未完成工作的线程。这是线程中基本异常安全的应用。
11.2 定位并发错误的技术
11.2.1 代码审阅——发现潜在的错误
如果让你的同事来审阅代码,他/她肯定对你的代码不是很熟悉。因此,他/她会从不同的角度来看你的代码,然后指出你没有注意的事情。如果你的同事都没有空,你可以叫朋友,或传到网络上,让网友审阅(注意,别传一些机密代码上去)。实在没有人审阅,不要着急。对于初学者,可以将代码放置一段时间——先去做应用的另外的部分,或是阅读一本书籍,亦或出去溜达溜达。在休息之后,当再集中注意力做某些事情(潜意识会考虑很多问题)。同样,当你做完其他事情,回头再看这段代码,就会有些陌生——你可能会从另一个角度来看你自己以前写的代码。
另一种方式就是自己审阅。可以向别人详细的介绍你所写的功能,可能并不是一个真正的人——可能要对玩具熊或橡皮鸡来进行解释,并且我个人觉得写一些比较详细的注释是非常有益的。在解释过程中,会考虑每一行过后,会发生什么事情,有哪些数据被访问了,等等。问自己关于代码的问题,并且向自己解释这些问题。我觉得这是种非常有效的技巧——通过自问自答,对每个问题认真考虑,这些问题往往都会揭示一些问题,也会有益于任何形式的代码审阅。
审阅多线程代码需要考虑的问题
并发访问时,哪些数据需要保护?
如何确定访问数据受到了保护?
是否会有多个线程同时访问这段代码?
这个线程获取了哪个互斥量?
其他线程可能获取哪些互斥量?
两个线程间的操作是否有依赖关系?如何满足这种关系?
这个线程加载的数据还是合法数据吗?数据是否被其他线程修改过?
当假设其他线程可以对数据进行修改,这将意味着什么?并且,怎么确保这样的事情不会发生?
我最喜欢最后一个问题,因为它让我去考虑线程之间的关系。通过假设一个bug和一行代码相关联,你就可以扮演侦探来追踪bug出现的原因。为了让你自己确定代码里面没有bug,需要考虑代码运行的各种情况。数据被多个互斥量所保护时,这种方式尤其有用,比如:使用线程安全队列(第6章),可以对队头和队尾使用独立的互斥量:就是为了确保在持有一个互斥量的时候,访问是安全的,必须保持有其他互斥量的线程不能同时访问同一元素。还需要特别关注的是,对公共数据的显式处理,使用一个指针或引用的方式来获取数据。
倒数第二个问题也很重要,因为这里很容易产生错误:先释放再获取一个互斥量的前提是,其他线程可能会修改共享数据。虽然很明显,但当互斥锁不是立即可见——可能因为是内部对象——就会不知不觉的掉入陷阱中。第6章已经了解到这种情况是怎么引起条件竞争的,以及如何给细粒度线程安全数据结构带来麻烦的。不过,非线程安全栈将top()和pop()操作分开是有意义的,当多线程并发的访问这个栈,问题会马上出现,因为在两个操作的调用间,内部互斥锁已经被释放,并且另一个线程对栈进行了修改。解决方案就是将两个操作合并,就能用同一个锁来对操作的执行进行保护,就消除了条件竞争的问题。
11.2.2 通过测试定位并发相关的错误
11.2.3 可测试性设计
测试多线程代码很困难,所以需要将其变得简单一些。很重要的一件事就是设计代码时,考虑其的可测试性。可测试的单线程代码设计已经说烂了,而且其中许多建议现在依旧适用。通常,如果代码满足一下几点,就很容易进行测试:
每个函数和类的关系都很清楚。
函数短小精悍。
测试用例可以完全控制被测试代码周边的环境。
执行特定操作的代码应该集中测试,而非分布式测试。
需要在完成编写后,考虑如何进行测试。
以上这些在多线程代码中依旧适用。实际上,我会认为对多线程代码的可测试性要比单线程的更为重要,因为多线程的情况更加复杂。最后一个因素尤为重要:即使不在写完代码后,去写测试用例,这也是一个很好的建议,能让你在写代码之前,想想应该怎么去测试它——用什么作为输入,什么情况看起来会让结果变得糟糕,以及如何激发代码中潜在的问题,等等。
并发代码测试的一种最好的方式:去并发化测试。如果代码在线程间的通讯路径上出现问,就可以让一个已通讯的单线程进行执行,这样会减小问题的难度。在对数据进行访问的应用进行测试时,可以使用单线程的方式进行。这样线程通讯和对特定数据块进行访问时只有一个线程,就达到了更容易测试的目的。
例如,当应用设计为一个多线程状态机时,可以将其分为若干块。将每个逻辑状态分开,就能保证对于每个可能的输入事件、转换或其他操作的结果是正确的;这就是单线程测试的技巧,测试用例提供的输入事件将来自于其他线程。之后,核心状态机和消息路由的代码,就能保证时间能以正确的顺序,正确的传递给可单独测试的线程上,不过对于多并发线程,需要为测试专门设计简单的逻辑状态。
或者,如果将代码分割成多个块(比如:读共享数据/变换数据/更新共享数据),就能使用单线程来测试变换数据的部分。麻烦的多线程测试问题,转换成单线程测试读和更新共享数据,就会简单许多。某些库会用其内部变量存储状态时需要小心,当多线程使用同一库中的函数,这个状态就会被共享。这的确是一个问题,并且问题不会马上出现在访问共享数据的代码中。不过,随着你对这个库的熟悉,就会清楚这样的情况会在什么时候出现。之后,可以适当的加一些保护和同步或使用B计划——让多线程安全并发访问的功能。
11.2.4 多线程测试技术
蛮力测试
代码有问题的时候,就要求蛮力测试一定能看到这个错误。这就意味着代码要运行很多遍,可能会有很多线程在同一时间运行。要是有bug出现,只能线程出现特殊调度的时候;代码运行次数的增加,就意味着bug出现的次数会增多。
当有几次代码测试通过,你可能会对代码的正确性有一些信心。如果连续运行10次都通过,你就会更有信心。如果你运行十亿次都通过了,那么你就会认为这段代码没有问题了。
自信的来源是每次测试的结果。如果你的测试粒度很细,就像测试之前的线程安全队列,那么蛮力测试会让你对这段代码持有高度的自信。另一方面,当测试对象体积较大的时候,调度序列将会很长,即使运行了十亿次测试用例,也不让你对这段代码产生什么信心。
组合仿真测试
名字比较口语化,我需要解释一下这个测试是什么意思:使用一种特殊的软件,用来模拟代码运行的真实情况。你应该知道这种软件,能让一台物理机上运行多个虚拟环境或系统环境,而硬件环境则由监控软件来完成。除了环境是模拟的以外,模拟软件会记录对数据序列访问,上锁,以及对每个线程的原子操作。然后使用C++内存模型的规则,重复的运行,从而识别条件竞争和死锁。
虽然,这种组合测试可以保证所有与系统相关的问题都会被找到,不过过于零碎的程序将会在这种测试中耗费太长时间,因为组合数目和执行的操作数量将会随线程的增多呈指数增长态势。这个测试最好留给需要细粒度测试的代码段,而非整个应用。另一个缺点就是,代码对操作的处理,往往会依赖与模拟软件的可用性。
所以,测试需要在正常情况下,运行很多次,不过这样可能会错过一些问题;也可以在一些特殊情况下运行多次,不过这样更像是为了验证某些问题。
使用专用库对代码进行测试
虽然,这个选择不会像组合仿真的方式提供彻底的检查,不过可以通过特别实现的库(使用同步原语)来发现一些问题,比如:互斥量,锁和条件变量。例如,访问某块公共数据的时候,就要将指定的互斥量上锁。数据被访问后,发现一些互斥量已经上锁,就需要确定相关的互斥量是否被访问线程锁住;如果没有,测试库将报告这个错误。当需要测试库对某块代码进行检查时,可以对相应的共享数据进行标记。
多个互斥量同时被一个线程持有时,测试库也会对锁的序列进行记录。如果其他线程以不同的顺序进行上锁,即使在运行的时候测试用例没有发生死锁,测试库都会将这个行为记录为“有潜在死锁”可能。
测试多线程代码时,另一种库可能会用到,以线程原语实现的库,比如:互斥量和条件变量;当多线程代码在等待,或是被条件变量通过notify_one()提醒的某个线程,测试者可以通过线程,获取到锁。就可以让你来安排一些特殊的情况,以验证代码是否会在这些特定的环境下产生期望的结果。
C++标准库实现中,某些测试工具已经存在于标准库中,没有实现的测试工具,可以基于标准库进行实现。
11.2.5 构建多线程测试代码
在特定时间内,需要安排一系列线程,同时去执行指定的代码段。两个线程的情况,就很容易扩展到多个线程。
首先,需要知道每个测试的不同之处:
环境布置代码,必须首先执行
线程设置代码,需要在每个线程上执行
线程上执行的代码,需要有并发性
并发执行结束后,后续代码需要对代码的状态进行断言检查
了解了各个代码块,就需要保证所有事情按计划进行。一种方式是使用一组使用承诺值来表示是否准备好,然后让std::promise等待(复制)一个std::promise std::shared_future来表示就绪状态。每个线程;主线程会等待每个线程上的承诺值设置后,才按下“开始”键。这就能保证每个线程能够同时开始,并且在准备代码执行完成后,并发代码就可以开始执行了;任何线程的特定设置都需要在设置承诺值前完成。最终,主线程会等待所有线程完成,并且检查其最终状态。还需要格外关心异常,所有线程在准备好的情况下,再按下“开始”键;否则,未准备好的线程就不会运行。
清单11.1 对一个队列并发调用push()和pop()的测试用例
1.void test_concurrent_push_and_pop_on_empty_queue()
2.{
threadsafe_queue<int> q;
3.
// 1
4.
5.std::promise<void> go,push_ready,pop_ready;
6.std::shared_future<void> ready(go.get_future());
// 2
// 3
7.
8.std::future<void> push_done;
9.std::future<int> pop_done;
// 4
10.
11.try
12.{
push_done=std::async(std::launch::async,
13.
// 5
14.[&q,ready,&push_ready]()
15.{
16.push_ready.set_value();
17.ready.wait();
q.push(42);
18.
}
19.
);
20.
pop_done=std::async(std::launch::async,
21.
// 6
22.[&q,ready,&pop_ready]()
23.{
24.pop_ready.set_value();
25.ready.wait();
26.return q.pop();
// 7
}
27.
);
28.
29.push_ready.get_future().wait();
30.pop_ready.get_future().wait();
31.go.set_value();
// 9
33.push_done.get();
// 10
34.assert(pop_done.get()==42);
// 8
32.
assert(q.empty());
35.
36.}
37.catch(...)
38.{
go.set_value();
39.
// 12
throw;
40.
}
41.
42.
// 11
}
11.2.6 测试多线程代码性能
选择以并发的方式开发应用,就是为了能够使用日益增长的处理器数量;通过处理器数量的增加,来提升应用的执行效率。因此,确定性能是否有真正的提高就很重要了(就像其他优化一样)。
并发效率中有个特别的问题——可扩展性——你希望代码能很快的运行24次,或在24芯的机器上对数据进行24(或更多)次处理,或其他等价情况。如8.4.2节中所述,当有重要的代码以单线程方式运行时,就会限制性能的提高。因此,在做测试之前,回顾一下代码的设计结构是很有必要的;这样就能判断,代码在24芯的机器上时,性能会不会提高24倍,或是因为有串行部分的存在,最大的加速比只有3。
对数据访问时,处理器之间会有竞争,会对性能有很大的影响。需要合理的权衡性能和处理器的数量,处理器数量太少,就会等待很久;处理器过多,又会因为竞争的原因等待很久。
因此,在对应的系统上通过不同的配置,检查多线程的性能就很有必要,这样可以得到一张性能图。最起码(如果条件允许)需要在一个单处理器的系统上和一个多处理核芯的系统上进行测试。
相关文章:
C++ 并发编程实战 第十一章 多线程应用的测试和除错
目录 11.1 与并发相关的错误类型 11.1.1 不必要的阻塞 11.1.2 条件竞争 11.2 定位并发错误的技术 11.2.1 代码审阅——发现潜在的错误 11.2.2 通过测试定位并发相关的错误 11.2.3 可测试性设计 11.2.4 多线程测试技术 11.2.5 构建多线程测试代码 11.2.6 测试多线程代…...
Redis实现API访问频率限制
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…...
BGP服务器租用价格表_腾讯云PK阿里云
BGP云服务器像阿里云和腾讯云均是BGP多线网络,速度更快延迟更低,阿里云BGP服务器2核2G3M带宽优惠价格108元一年起,腾讯云BGP服务器2核2G3M带宽95元一年起,阿腾云分享更多云服务器配置如2核4G、4核8G、8核16G等配置价格表如下&…...
时序分解 | Matlab实现SSA-VMD麻雀算法优化变分模态分解时间序列信号分解
时序分解 | Matlab实现SSA-VMD麻雀算法优化变分模态分解时间序列信号分解 目录 时序分解 | Matlab实现SSA-VMD麻雀算法优化变分模态分解时间序列信号分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 SSA-VMD麻雀搜索算法SSA优化VMD变分模态分解 可直接运行 分解效果好…...
【CSS如何实现双飞翼布局】
双飞翼布局是一种基于浮动布局的设计模式,主要用于实现三栏布局。它的主要特点是左右两列是浮动的,中间一列使用margin负值来达到“自适应”的效果。这种布局模式可以避免使用嵌套的div,同时也可以保证页面的语义结构清晰。以下是实现双飞翼布…...
服务注册发现机制
二、注册中心选型 1. zk和eureka的区别 zk:CP设计(强一致性),目标是一个分布式的协调系统,用于进行资源的统一管理。 当主节点crash后,需要进行leader的选举,在这个期间内,zk服务是不可用的(当然…...
【postgresql 基础入门】多表联合查询 join与union 并,交,差等集合操作,两者的区别之处
多表数据联合查询 专栏内容: postgresql内核源码分析手写数据库toadb并发编程 开源贡献: toadb开源库 个人主页:我的主页 管理社区:开源数据库 座右铭:天行健,君子以自强不息;地势坤&#x…...
很可惜,pyinstaller不是万能的
近期活不算少,但是真正新的东西很少,基本都是做些相似的功能,所以有精力想想之前悬而未决的问题,比如前两天写的加快软件启动速度的探索,这几天又想起一个之前没有解决的问题,这个问题之前也在博客写过&…...
0/1背包问题
例题HDU-2602 Problem Description Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave … The bone collector had a big bag wi…...
Redis入门到精通——00数据类型
1、String 1.1、介绍 String 是最基本的 key-value 结构,key 是唯一标识,value 是具体的值,value其实不仅是字符串, 也可以是数字(整数或浮点数),value 最多可以容纳的数据长度是 512M 1.2、…...
PADS9.5使用记录
目录 一、概述 二、PADS Logic IN4148二极管封装 SOD-123封装 SOD-323封装 SOD-523封装 2N3904 1AM 三极管封装 78L05 7533-1 一、概述 PADS Logic 原理图绘制PADS Layout PCB 封装设计PADS Router 布线 二、PADS Logic …...
Axios post请求出现500错误
笔者在编写前端form表单传后端数据的时候,出现了以下问题 一、问题场景 当我用axios发送post请求的时候,出现了500错误 笔者找了很长时间错误,代码没问题,后端接口也没问题,后来发现问题出在实体类上了 当前端post请…...
【Leetcode】171.Excel 表列序号
一、题目 1、题目描述 给你一个字符串 columnTitle ,表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。 例如: A -> 1 B -> 2 C -> 3 … Z -> 26 AA -> 27 AB -> 28 … 示例1: 输入: columnTitle = "A" 输出: 1示例2: 输入: colu…...
2023湖南省赛游记/题解
省赛拖了大哥们的后腿,感觉随便补个正常一队水平的人,我们一队肯定能AK。只能说自己真的菜,全程帮不上什么忙,还负贡献,真的想笑 B 暴力sg #include <bits/stdc.h> #define ll long long #define ull unsigned…...
海信电视U8KL使用体验:参数卷,画质技术也独有!
每个家庭成员对电视都有不同需求,如何能做到兼顾?看似需求众口难调,其实一台海信电视就能满足所有啦。 海信电视的参数不仅是最卷的,同时画质技术还是国内独有的,能把这样一台优秀的电视搬回家,无论电影、…...
E. Mishap in Club
题目: 样例1: 输入 --输出 1 样例2: 输入 --- 输出 3 思路: 数学贪心模拟思路,由于不知道在俱乐部的人数和在外面的人数,又要尽可能少的人数,那么定义两个变量,一个是里面的人数 i…...
UE4 自带体积云应用
新建空关卡 点击该选项 全部点击一遍 拖进场景...
RTP/RTCP 协议讲解
文章目录 前言一、RTP 协议1、RTP 协议概述2、RTP 工作机制3、RTP 协议的报文结构4、wireshark 抓取 RTP 报文 二、RTCP 协议1、RTCP 协议概述2、RTCP 工作机制3、RTCP 数据报4、wireshark 抓取 RTCP 报文 三、RTSP 和 RTP 的关系四、易混淆概念1、RTP over UDP 和 RTP over RT…...
倒计时15天!百度世界2023抢先看
近日消息,在10月17日即将举办的百度世界2023上,百度创始人、董事长兼首席执行官李彦宏将带来主题演讲,“手把手教你做AI原生应用”。 增设社会报名,有机会获得精美伴手礼 目前,百度世界大会已经开放公众参会报名&…...
Redis 哈希(Hash)数据类型和命令(数据类型 二)
基本概念 Hash是一个键值对的集合,其中每个键都是唯一的。每个键都可以关联多个字段和值,这使得Hash非常适合存储对象或结构化数据。 常用命令 存储、获取、删除:hset、hget、hdel # 添加键为name值为lin hset student name lin # 获取 h…...
[Linux]线程互斥
[Linux]线程互斥 文章目录 [Linux]线程互斥线程并发访问问题线程互斥控制--加锁pthread_mutex_init函数pthread_mutex_destroy函数pthread_mutex_lock函数pthread_mutex_unlock函数锁相关函数使用示例使用锁的细节加锁解锁的实现原理 线程安全概念常见的线程不安全的情况常见的…...
leetcode-239-滑动窗口最大值
题意描述: 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例: 输入:nums [1,3,-1,…...
基于大语言模型的智能问答系统应该包含哪些环节?
一个完整的基于 LLM 的端到端问答系统,应该包括用户输入检验、问题分流、模型响应、回答质量评估、Prompt 迭代、回归测试,随着规模增大,围绕 Prompt 的版本管理、自动化测试和安全防护也是重要的话题,本篇文章就来探索下这个过程…...
【Cesium创造属于你的地球】相机系统
相机系统里面有setView,flyTo,lookAt,viewBoundingsphere这几种方法,以下是相关的使用方法,学起来!!! setView 该方法可以直接切换相机视口,从而不需要通过一个飞入的效…...
运维困局下确保系统稳定的可行性
业务高速发展背后的困局 随着业务的快速发展,运维体系也逐步的完善起来。业务的稳定性和服务质量也在监控、可用性等体系的相互环抱下健康地成长。所有的问题、故障及影响稳定性的因素都在可控、可收敛的范围内,一切都向着好的方向发展。 这一切的背后…...
springmvc中DispatcherServlet关键对象
以下代码为 spring boot 2.7.15 中自带的 spring 5.3.29 RequestMappingInfo 请求方法相关信息封装,对应的信息解析在 RequestMappingHandlerMapping 的 createRequestMappingInfo() 中实现。 对于 RequestMapping 赋值的相关信息进行解析 protected RequestMappi…...
某微e-office协同管理系统存在任意文件读取漏洞复现 CNVD-2022-07603
目录 1.漏洞概述 2.影响版本 3.漏洞等级 4.漏洞复现 5.Nuclei自动化扫描POC 某微e-office协同管理系统存在任意文件读取漏洞分析 CNVD-2022-07603https://blog.csdn.net/qq_41490561/article/details/133469649...
消息驱动 —— SpringCloud Stream
Stream 简介 Spring Cloud Stream 是用于构建消息驱动的微服务应用程序的框架,提供了多种中间件的合理配置 Spring Cloud Stream 包含以下核心概念: Destination Binders:目标绑定器,目标指的是 Kafka 或者 RabbitMQ࿰…...
使用Apache HttpClient爬取网页内容的详细步骤解析与案例示例
Apache HttpClient是一个功能强大的开源HTTP客户端库,本文将详细介绍如何使用Apache HttpClient来爬取网页内容的步骤,并提供三个详细的案例示例,帮助读者更好地理解和应用。 一、导入Apache HttpClient库 在项目的pom.xml文件中添加依赖&a…...
传输层协议—UDP协议
传输层协议—UDP协议 文章目录 传输层协议—UDP协议传输层再谈端口号端口号范围划分pidofnetstat UDP协议端格式UDP报文UDP特点UDP缓冲区基于UDP的应用层协议 传输层 在学习HTTP/HTTPS等应用层协议时,为了方便理解,可以简单认为HTTP将请求和响应直接发送…...
wordpress固定链接文章别名/如何做一个自己的网站
一.虚拟账号 顾明思意,在本地账号库中并不存在的账号为虚拟账号。在服务器内部会将虚拟账号映射成为一个本地账号在邮件服务器上进行操作。对于用户来说并没有任何影响。避免网络抓包得到账号密码。这样可以提高服务器的安全性。 二.lamp环境 linuxapachemysqlphp 环…...
做网站和做系统有什么不同/推广普通话的手抄报
这篇文章《用openpose来预测篮球罚篮准确性》,当中用到了很多比较好的方法,比如机器学习的逻辑回归进行多元二项的分类问题;用石川馨的质量工程工具——帕累托图,进行逻辑回归模型精确度的确定。 1.摘要 OpenPose由卡内基梅隆大…...
北京疫情防控网络发布预告/上海官网seo
面向网络游戏的“云”应用平台浅析——2009-1-15 CTO俱乐部第一次聚会“云计算”后记 CTO俱乐部第一次聚会的主题是“云计算”,关于聚会的概述发表在: 2009-1-15 CTO俱乐部第一次聚会,http://blog.csdn.net/hu_zhenghui/archive/2009/01/1…...
公众号seo排名优化/seo网络推广企业
目录 1.tzselect 2.修改配置文件来修改时区 3.链接到上海时区文件 4.执行完上述过程后 做完软连接后发现还是不行重新安装下 1.tzselect 执行tzselect命令-->选择Asia-->选择China-->选择east China - Beijing, Guangdong, Shanghai, etc-->然后输入1…...
中职国示范建设网站/seo网站推广杭州
由donnywals于2020年9月7日发布 如果您是一位正在寻找工作的程序员,则很有可能在某个时候必须进行一次编程面试。 每个公司进行这些面试的方式都不同。 有些人可能会让您解决一些严重的计算机科学问题,有些人可能会给您提出与您要面试的工作相关的任务&a…...
wordpress视频解析/建设网官方网站
新的一年已经开启,不确定性的环境让很多公司的岗位都会有不确定性的因素,如果公司让你轮岗,你会怎么想?如何去理解自己的工作岗位及面对公司轮岗,我是这样想的,与你一起共享:在知识经济时代&…...