题目描述
输入整数m,n,k,求mn mod k的值。m,n,k*k为长整型范围内的自然数。
输入
输入一行3个整数,分别为m,n和k。
输出
输出一行一个整数,表示结果。
样例输入
复制样例数据
2 10 9
样例输出
7
#include<bits/stdc++.h> using namespace std; typedef long int ll; int main() { ll m,n,k; cin>>m>>n>>k; ll res=1%k; while(n) { if(n&1) res=res*m%k; m=m*m%k; n>>=1; // cout<<res<<endl; } cout<<res<<endl; }
1.可能是ssh服务没有开启
使用 service sshd status 查看ssh服务是否开启。
如果没有开启(sshd is stopped)
命令行输入service sshd start即可。
注意:这样手动开启的ssh服务,每次重新启动后ssh还是会关闭。可以通过chkconfig sshd on命令来设置开机自启动。
2.可能是没有允许用户通过ssh登陆root用户
输入 vi /etc/ssh/sshd_config
找到PermitRootLogin这一行,将参数改为yes即可。(记得重启一下ssh服务)
3.可能是虚拟机的网络模式没有配置对。
将虚拟机的网络适配器配置为NAT模式即可。
注:在此模式下主机ping的通虚拟机,虚拟机ping不通主机
顺便说一下桥接模式,在该模式下,虚拟机对于外部网络来说拥有独立的物理地址,路由器将会给他分配一个独立的ip。如果说你使用桥接模式无法访问外部网络,那么可能的情况就是你公司的网络是将mac地址和ip绑定的。路由不给虚拟机分配ip,那它自然也就无法访问外网。
Ubuntu 18.04 系统安装完成后,我们从零开始搭建基于docker 的深度学习环境。整个安装过程主要分为4步:(1)安装nvidia驱动(2)安装docker (3)安装nvidia docker (4)拉取Deepo镜像。最后,我们通过tensorflow运行一个MNIST手写字符识别的例子来进行验证。
一. 安装nvidia驱动 1. 首先禁用nouveau驱动
把 nouveau 驱动加入黑名单
sudo gedit /etc/modprobe.d/blacklist-nouveau.conf
在文件 blacklist-nouveau.conf 中加入如下内容:
blacklist nouveau
options nouveau modeset=0
禁用 nouveau 内核模块
sudo update-initramfs -u
重启
sudo reboot
重启后再次进入命令行
lsmod | grep nouveau
如果没有任何输出说明禁用成功
2. 安装nvidia驱动
需要安装新版本的驱动可以先添加源:
sudo add-apt-repository ppa:graphics-drivers/ppa
sudo apt update
然后执行以下命令,列出显卡可用的和推荐的驱动程序
ubuntu-drivers devices
选择一个版本进行安装,这里选择nvidia-driver-430
sudo apt install nvidia-driver-430
安装完成后重启
sudo reboot
3.验证是否安装成功
输入命令
nvidia-smi
若出现下图则表示安装成功:
二. 安装docker docker的安装过程请参考官方地址https://docs.docker.com/install/linux/docker-ce/ubuntu/。这里的docker指的是docker-ce(docker社区版本),采用基于仓库的方式进行安装。
1. 设置仓库
a 转载于:https://www.cnblogs.com/alex-gc/p/11636866.html
在ubuntu系统如何卸载OpenVINO的步骤:
(1)进入安装路径,找到openvino_toolkit_uninstaller
cd /opt/intel/openvino/openvino_toolkit_uninstaller (2)如果使用的ubuntu有GNOME桌面,尽量使用GUI界面卸载,比较方便。请根据操作提示一步步卸载。
sudo ./uninstall_GUI.sh 卸载完成后cd 到 /opt/intel目录,看到安装包已经被删除了。
(3)打开 ~/.bashrc,删除环境变量
source /opt/intel/openvino/bin/setupvars.sh (4)在home目录分别删除 openvino_models、inference_engine_demos_build、inference_engine_samples_build文件夹。
最近项目用node做微服务,有一部分需要处理图片和html转pdf,查了资料,整理如下,希望对大家有用。
图片处理 查资料时,很多同仁说gm好,功能很强大,可以处理图片,pdf转图片等,但细究之后发现需要在服务器上安装第三方软件GraphicsMagick 或 ImageMagick,比较麻烦,遂放弃。
sharp
Sharp非常好用,跨平台,一键安装(npm install sharp);可以处理一切常见的图片格式(JPEG、PNG、WebP、TIFF、Gif等等);C语言编写,处理速度快,其执行JPEG格式图片调整的速度是 ImageMagick 和GraphicsMagick的8倍,这主要依赖于可用CPU核的数量,这一切能顺利进行要感谢libuv 和 Promises/A+ 的支持。
常见用法如下: const sharp = require('sharp'); sharp('input.jpg') .rotate() .resize(200) .toBuffer() .then( data => ... ) .catch( err => ... ); 具体用法参考文章服务端图片处理利器——sharp 进阶操作指南
images
images也是一个不错的图片处理工具,虽说功能可能少些,但用起来颇为不错。 const images = require("images"); images(images("image/test.jpg"),200,200,500,500) .resize(100) .save("image/new.jpg"); 具体用法参考文章images基础使用
仅仅获取图片长和宽可以用下面两个工具,小巧。 1:图像维度获取: image-size;
2:网络图像维度获取(不用下载): http-image-size 。
Html To PDF phantom
这是我最推荐的npm包,功能强大,它支持样式渲染,图片加载,没有遇到失真问题,还可以通过url直接生成PDF文件,不友好的地方就是只能输出pdf文件保存到本地,不能以stream或buffer方式输出。
phantom可以设置pdf样式,如大小(A3/A4/A5/letter),页边距,页眉页脚,页面方向等,还支持分页。 const phantom = require('phantom'); phantom.create().then(function(ph) { ph.createPage().then(function(page) { page.open("https://www.oracle.com/index.html").then(function(status) { page.property('viewportSize',{width: 10000, height: 500}); page.
torchvision使用的PILLOW做图像处理实在太慢了,pillow-simd要快一些。
Windows下比较简单的安装方法是,从https://www.lfd.uci.edu/~gohlke/pythonlibs/下载build好了的whl文件,然后cmd输入
$ pip uninstall pillow $ pip install -U --force-reinstall Pillow_SIMD-6.0.0.post0-cp36-cp36m-win_amd64.whl
题面 <center> 1917: [HNOI2008]越狱 <center>
<center>时间限制:1秒 内存限制:162MB<center>
题目描述
监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种。如果
相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱
输入
输入两个整数M,N.1<=M<=10^8^,1<=N<=10^12^
输出
可能越狱的状态数,模100003取余
样例输入
2 3
样例输出
6
提示
6种状态为(000)(001)(011)(100)(110)(111)
题解 每个房间的一个人信仰M个宗教中的一种,则N个房间共有M^N^种状态,其中不可越狱的状态:第一个房间的人可从M个宗教中选一,剩余N-1个房间的人不能和前一个人的宗教相同(否则会越狱),有(M-1)个宗教选择,共M*(M-1)^(N-1)^种状态。则最终可越狱的状态:M^N^- M*(M-1)^(N-1)^。最终答案:((M^N^- M*(M-1)^(N-1)^))%mod。运用费马小定理(a^b^%p=a^b%(p-1)^%p)进行降幂,并运用各种求余公式整理得:
(M^N%(mod-1)^%mod- M%mod*((M-1)^(N-1)%(mod-1)^%mod)+mod)%mod
最后,对其进行计算即可。
## 源码
#include <iostream> using namespace std; typedef long long ll; const ll mod=1e5+3; ll fun(ll a,ll b){ ll i; ll ans=1; for(i=0;i<b;i++){ ans*=a; ans%=mod; } return ans; } int main(int argc, char** argv) { ll n,m,a,b,c,d,e; cin>>m>>n; a=n%(mod-1); b=fun(m,a); c=(n-1)%(mod-1); d=fun(m-1,c); m%=mod; d*=m; d%=mod; e=(b-d+mod)%mod; cout<<e; return 0; }
题面 <center> 5758: [Jsoi2016]位运算<center>
<center>时间限制:20秒 内存限制:512MB <center>
题目描述
JYY最近在研究位运算。他发现位运算中最有趣的就是异或(xor)运算。对于两个数的异或运算,JYY发现了一个结论:两个数的异或值为0当且仅当他们相等。于是JYY又开始思考,对于N个数的异或值会有什么性质呢?
【问题描述】
JYY想知道,如果在0到R-1的范围内,选出N个不同的整数,并使得这N个整数的异或值为0,那么一共有多少种选择的方法呢?(选择的不同次序并不作重复统计,请参见样例)JYY是一个计算机科学家,所以他脑海里的R非常非常大。为了能够方便的表达,如果我们将R写成一个0-1串,那么R是由一个较短的0-1串S重复K次得到的。比如,若S=“101”,K=2,那么R的2进制表示则为“101101”。由于计算的结果会非常大,JYY只需要你告诉他选择的总数对10^9+7取模的结果即可。
输入
第一行包含两个正整数N和K。
接下来一行包含一个由0和1组成的字符串S
我们保证S的第一个字符一定为1。
3<=N<=7,1<=k<=10^5,1<=|S|<=50
输出
一行一个整数,表示选择的方案数对10^9+7取模的值。
样例输入
3 1
100
样例输出
1
提示
对于第一个样例, 唯一的一种选择方法是选择 {1, 2, 3}。
题解 我推出了规律:所有N个数的第i位中‘1’的个数必须为偶数,才能使最终结果为0,但是接下来就没有思路了……
在网上搜了题解:题解链接,但是题解过于简单,代码也没啥注释,也许是wtcl并没有看明白,又研究了好久才搞懂,并把代码加上了注释。
大体思路是这样的:首先,定义了一个结构体用来定义矩阵,其中包括矩阵的初始化(类似于Java的构造方法);然后定义了两个函数(方法):矩阵的乘法和矩阵幂;以上都是辅助性质的。以下为主要内容:为实现N个数不相同,规定A~1~<A~2~<……<A~N~,用trans函数(方法)实现,然后进行状态压缩用lim的二进制值来表示N个数每一位的取值(0 or 1),最后求出一个|s|的结果,再运用矩阵快速幂求出k个|s|的结果。
源码 #include <iostream> #include <cstring> using namespace std; const int mod=1e9+7; int n,k,len,lim,f[55][130]; char s[55]; typedef unsigned long long ull; struct matrix {//矩阵结构体定义 ull a[130][130]; matrix(int t=0) {//初始化一个对角线为t,其他位置为0的矩阵 memset(a,0,sizeof(a)); for(int i=0;i<=lim;i++) a[i][i]=t; } }A; matrix fun(matrix a,matrix b) {//矩阵乘法 matrix c(0); for(int i=0;i<=lim;i++) for(int k=0;k<=i;k++) if(a.
https://www.jianshu.com/p/66b91bec12e3
elasticsearch——Rest Client 0.2372018.05.10 15:23:03字数 1287阅读 8223 elasticsearch版本迭代太快,项目中用的5.X版本,java client使用了新推出的Rest Client。而网上的client大多是还是TransportClient。组里封装的EsClient不满足业务需求,只能自己研究下Rest Client。Rest Client为推荐使用,TransportClient将在未来版本中废弃。新版本的很多api都发生了变化,改名了或者换地方了。。。
这里提供一个elasticsearch5.6 java rest client的中文文档:https://legacy.gitbook.com/book/quanke/elasticsearch-java-rest/details。本文章只是简单应用,详细细节参考此文档。
介绍 java rest client有两个实现类,分别是RestClient和RestHighLevelClient。前者是一个低级客户端,通过Http与elasticsearch集群进行通信,可以做到 负载均衡、故障转移、持久化链接、自动发现集群节点等功能,同时支持所有elasticsearch版本,但是需要自己对请求和相应做编解码(自己写JSON);后者是一个高级客户端,对增删改差进行了封装,不需要处理编解码,类似之前的TransportClient,但是兼容性较差,对客户端和集群版本要求较高。
因为RestClient没有提供增删改差方法,只能自己写json并选择Http请求的方法进行实现,一般使用较少,只有RestHighLevelClient无法满足的情况下才会使用。这里主要介绍RestHighLevelClient。
RestHighLevelClient RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClient);
RestHighLevelClient仅仅是对RestClinet的一个封装。支持异步请求。
search api 请求 构造查询主要用到两个类:SearchRequest和SearchSourceBuilder。
SearchRequest searchRequest = new SearchRequest(); //穿件SeachRequest,Without arguments this runs against all indices. SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();// 大多数的搜索参数被添加到 SearchSourceBuilder 。它为每个进入请求体的每个东西都提供 setter 方法。 searchSourceBuilder.query(QueryBuilders.matchAllQuery()); // 添加一个 match_all 查询到 searchSourceBuilder 。 searchRequest.source(searchSourceBuilder); //将searchSourceBuilder添加到searchRequest 这里构造了一个查询请求,内容为一个match_all查询。
SearchRequest为最终的查询请求封装,而查询的大部分细节由SearchSourceBuilder指定。
首先来看一下常用的几个SearchRequest方法
SearchRequest searchRequest = new SearchRequest("
https://www.jianshu.com/p/f4d322415d29
1.简介 ES为了避免深分页,不允许使用分页(from&size)查询10000条以后的数据,因此如果要查询第10000条以后的数据,要使用ES提供的 scroll(游标) 来查询
假设取的页数较大时(深分页),如请求第20页,Elasticsearch不得不取出所有分片上的第1页到第20页的所有文档,并做排序,最终再取出from后的size条结果作爲最终的返回值
假设你有16个分片,则需要在coordinate node彙总到 shards* (from+size)条记录,即需要16*(20+10)记录后做一次全局排序
所以,当索引非常非常大(千万或亿),是无法使用from + size 做深分页的,分页越深则越容易OOM,即便不OOM,也很消耗CPU和内存资源
因此ES使用index.max_result_window:10000作爲保护措施 ,即默认 from + size 不能超过10000,虽然这个参数可以动态修改,也可以在配置文件配置,但是最好不要这麽做,应该改用ES游标来取得数据
2.scroll游标原理 可以把 scroll 理解爲关系型数据库里的 cursor,因此,scroll 并不适合用来做实时搜索,而更适用于后台批处理任务,比如群发
scroll 具体分爲初始化和遍历两步
初始化时将所有符合搜索条件的搜索结果缓存起来,可以想象成快照
在遍历时,从这个快照里取数据
也就是说,在初始化后对索引插入、删除、更新数据都不会影响遍历结果
游标可以增加性能的原因,是因为如果做深分页,每次搜索都必须重新排序,非常浪费,使用scroll就是一次把要用的数据都排完了,分批取出,因此比使用from+size还好
3.具体实例 初始化
请求
注意要在URL中的search后加上scroll=1m,不能写在request body中,其中1m表示这个游标要保持开启1分钟
可以指定size大小,就是每次回传几笔数据,当回传到没有数据时,仍会返回200成功,只是hits裡的hits会是空list
在初始化时除了回传_scroll_id,也会回传前100笔(假设size=100)的数据
request body和一般搜索一样,因此可以说在初始化的过程中,除了加上scroll设置游标开启时间之外,其他的都跟一般的搜寻没有两样 (要设置查询条件,也会回传前size笔的数据)
POST 127.0.0.1:9200/my_index/_search?scroll=1m `注意这里的地址` { "query":{ "range":{ "createTime": { "gte": 1522229999999 } } }, "size": 1000 } 返回结果
{ "_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAfv5-FjNOamF0Mk1aUUhpUnU5ZWNMaHJocWcAAAAAAH7-gBYzTmphdDJNWlFIaVJ1OWVjTGhyaHFnAAAAAAB-_n8WM05qYXQyTVpRSGlSdTllY0xocmhxZwAAAAAAdsJxFmVkZTBJalJWUmp5UmI3V0FYc2lQbVEAAAAAAHbCcBZlZGUwSWpSVlJqeVJiN1dBWHNpUG1R", "took": 2, "timed_out": false, "_shards": { "total": 5, "
问题描述:
前端同事使用Vue.js框架,利用vue-route结合webpack编写了一个单页路由项目,运维协助在服务器端配置nginx。部署完成后,访问首页没问题,从首页里打开二级页面没问题,但是所有的二级页面打开后,再次刷新,就会出现404现象
问题原因:
刷新页面时访问的资源在服务端找不到,因为vue-router设置的路径不是真实存在的路径。
如上的404现象,是因为在nginx配置的根目录/Data/app/xqsj_wx/dist下面压根没有loading这个真实资源存在,这些访问资源都是在js里渲染的。
服务端nginx的一开始配置如下(假设域名为:testwx.wangshibo.com):
[root@test-huanqiu ~]# cat /Data/app/nginx/conf/vhosts/testwx.wangshibo.com.conf server {
listen 80;
server_name testwx.wangshibo.com;
root /Data/app/xqsj_wx/dist;
index index.html;
access_log /var/log/testwx.log main;
}
如上出现404的原因是由于在这个域名根目录/Data/app/xqsj_wx/dist下面压根就没有loading这个真实目录存在。
问题解决:
在nginx配置里添加vue-route的跳转设置(这里首页是index.html,如果是index.php就在下面对应位置替换),正确配置如下(添加下面标红内容):
[root@test-huanqiu ~]# cat /Data/app/nginx/conf/vhosts/testwx.wangshibo.com.conf server {
listen 80;
server_name testwx.wangshibo.com;
root /Data/app/xqsj_wx/dist;
index index.html;
access_log /var/log/testwx.log main;
location / {
try_files $uri $uri/ @router;
index index.html;
}
location @router {
rewrite ^.*$ /index.html last;
}
}
重启nginx后,问题就迎刃而解了。
[总结:nginx配置文件里一定要定义access和error日志,出现问题要第一时间查看日志(error)
本文转载:https://www.cnblogs.com/kevingrace/p/6126762.html
转载于:https://www.cnblogs.com/mandy-dyf/p/11611720.html
T版是块难解的砖头,之前一直没有找到稳定解锁办法,经过多次不写努力和实验,终于解决
不管是用超雪卡贴还是GPP卡贴,第一次先用连接WIFI激活手机!
注意:一定不要用ICCID通用激活,或者是TMSI+ICCID自动模式激活!
激活成功以后,弹出卡槽。
设置-通用-还原-抹掉所有内容和设置,点击确定。
手机开始还原,在所有进度条走完重启进入第一进入激活界面后,将卡槽按进去。
此时打开电脑连接iTunes,iTunes会自动激活手机,并且出现选择让设置为新的iPhone,这时继续在手机上操作,下一步继续激活手机,直到手机桌面。
此时左上角信号已经出来了,显示中国移动或者中国联通,打开数据漫游,就可以上网了
此时显示是中国移动/联通LTE。
刷入中国电信38.0 IPCC文件,把LTE变4G,让不完美解锁变完美解锁!
附上IPCC文件下载链接:链接: https://pan.baidu.com/s/1qQKdrY15bieKuoqRfN1wMw 提取码: 2333
转载于:https://www.cnblogs.com/1oo88/p/11609397.html
html 代码
<video controls="controls" id="video" poster="放图片,为了防止视频没加载完成显示空白" autoplay="autoplay自动播放">
<source src="视频路径" type="video/mp4" id="source"/>
Your browser does not support the video tag.
</video>
JS代码
var playimg=document.getElementById("playimg");//一个播放按钮的图片
var video=document.getElementById("video");//video标签对象
video.currentTime;//获取视频当前播放时间
//如果视频加载完成 播放按钮图片显示,视频图片设置为空,显示视频内容
video.οncanplay=function(){
$("#playimg").show();
$("#video").attr("poster","");
}
//视频播放事件,点击播放可以记录学习进度,有获取当前视频播放时间属性
video.οnplay=function(){
if($("#is_record").val()==null || $("#is_record").val()==''){
$.ajax({
type : "post",
url : ctx+"/traincourserecord/save.shtml",
data:{
con_id : $('.now_play').data("id"),
course_id : $("#course_id").val()
},
success : function(data) {
if(data.flag){
}else{
parent.layer.msg("记录学习出现错误");
}
},
error: function(data) {
parent.layer.msg("记录学习出现错误");
}
});
}
$("#playimg").hide();
Opencv C++ 基本数据结构 Mat Mat构造单通道Mat对象获取单通道Mat的基本信息以三行两列的矩阵为例1、获取行数和列数2、使用成员函数size()获取矩阵的尺寸3、使用成员函数channels()获取矩阵的通道数4、使用成员函数total获得面积(行数乘列数)5、成员变量dims(维数) 访问单通道对象中的值1、使用成员函数at2、利用成员函数ptr3、使用成员函数isContinuous 和 ptr4、使用成员变量step和data 向量类Vec(构建多通道Mat的基础)构造多通道Mat对象访问多通道对象中的值1、使用成员函数at2、利用成员函数ptr3、使用成员函数isContinuous 和 ptr4、使用成员变量step和data5、分离通道5、合并通道 获得Mat中某一个区域的值1、使用row(i)或col(j)得到矩阵的第i行j列2、使用rowRange或colRange得到矩阵的连续行或连续列3、使用rowRange或colRange得到矩阵的连续行或连续列4、使用Rect类 Mat Mat代表矩阵,该类声明在头文件opencv2/core/core.hpp中
其构造函数为:
Mat(int rows, int cols, int type) rows代表行数,cols代表列数
type可以设置为 CV_8UC(n)、CV_8SC(n)、CV_16SC(n)、、CV_16UC(n)、CV_32FC(n)、*、CV_32SC(n)、CV_64FC(n)
其中8U、8S、16S、16U、32S、32F、64F前的数字代表Mat中每一个数值的位数
U代表uchar类型、S代表int类型、F代表浮点型(32F为float、64F为double)其他类似。
构造单通道Mat对象 如代码所示:
# include <opencv2\core\core.hpp> using namespace cv; int main() { //构造两行三列的float型矩阵 Mat m = Mat(2, 3, CV_32FC(1)); //利用Size对象构造两行3列矩阵,Size(列,行) Mat m1 = Mat(Size(3, 2), CV_32FC(1)); //使用Mat类中的成员函数create完成Mat对象构造 Mat m2; m2.create(Size(2, 3), CV_32FC1); //构造零矩阵和1矩阵 Mat o = Mat::ones(2, 3, CV_32FC1); Mat z = Mat::zeros(Size(3,2), CV_32FC1); //初始化小型矩阵 Mat m = (Mat_<int>(2, 3) << 1, 2, 3, 4, 5, 6; return 0; } 获取单通道Mat的基本信息 注:单通道与ndarray中的二维对应,多通道与ndarray的三维对应
python实例 批量重命名文件夹中的图片文件 完整代码:
# -*- coding:utf8 -*- import os class BatchRename(): ''' 批量重命名文件夹中的图片文件 ''' def __init__(self): self.path = '文件目录' #表示需要命名处理的文件夹 def rename(self): filelist = os.listdir(self.path) #获取文件路径 total_num = len(filelist) #获取文件长度(个数) i = 1 #表示文件的命名是从1开始的 for item in filelist: if item.endswith('.jpg'): src = os.path.join(os.path.abspath(self.path), item) dst = os.path.join(os.path.abspath(self.path), ''+'normal.'+str(i) + '.jpg')#处理后的格式也为jpg格式的,当然这里可以改成png格式 try: os.rename(src, dst) #print ('converting %s to %s ...' % (src, dst)) i = i + 1 except: continue print ('total %d to rename & converted %d jpgs' % (total_num, i)) if __name__ == '__main__': demo = BatchRename() demo.
对于高并发的任务,有些任务是相互独立的,任务与任务之间没有依赖关系,因此可以采用 master - worker 模式。
master 用于接受任务和分发任务给 worker,并将 worker 返回的结果组装返回给调用方。因此该模式是异步的。
要用到组件有:任务队列、任务和worker线程映射、任务和结果集映射
private ConcurrentLinkedQueue<Task> taskQueue = new ConcurrentLinkedQueue<>(); private HashMap<String, Runnable> taskThreadMap = new HashMap<>(); private ConcurrentHashMap<String, Result> taskResultMap = new ConcurrentHashMap<>(); 对于任务队列,master 用于接受任务, worker 线程从任务集中取任务,涉及到多 worker 线程操作同一任务集,因此需要使用线程安全的集合 ConcurrentLinkedQueue。
任务和worker线程映射 用于限制 worker 线程数量,在 master 中控制。因为只有一个 master 线程,因此不需要使用线程安全的集合类。
任务和结果集映射 用于 worker 将结果返回给 master 线程。涉及到多个 worker 线程,因此需要使用线程安全的 ConcurrentHashMap 保存任务和结果的映射。
转载于:https://www.cnblogs.com/zhaopengcheng/p/11602996.html
PEP 8 规范
PEP 是 Python Enhancement Proposal 的缩写,翻译过来叫“Python 增强规范”。
缩进规范
PEP 8 规范告诉我们,请选择四个空格的缩进,不要使用 Tab,更不要 Tab 和空格混着用。 第二个要注意的是,每行最大长度请限制在 79 个字符。
空行规范
PEP 8 规定,全局的类和函数的上方需要空两个空行,而类的函数之间需要空一个空行。
空格规范
函数的参数列表中,调用函数的参数列表中会出现逗号,请注意逗号后要跟一个空格,这是英语的使用习惯,也能让每个参数独立阅读,更清晰。
冒号后面也要跟一个空格。在#后、注释前加一个空格。操作符,例如+,-,*,/,&,|,=,==,!=,请在两边都保留空格。不过与此对应,括号内的两端并不需要空格。 换行规范
控制每行的最大长度不超过 79 个字符,但是有时候,函数调用逻辑过长而不得不超过这个数字时按以下规范:
def solve1(this_is_the_first_parameter, this_is_the_second_parameter, this_is_the_third_parameter, this_is_the_forth_parameter, this_is_the_fifth_parameter, this_is_the_sixth_parameter): return (this_is_the_first_parameter + this_is_the_second_parameter + this_is_the_third_parameter + this_is_the_forth_parameter + this_is_the_fifth_parameter + this_is_the_sixth_parameter) def solve2(this_is_the_first_parameter, this_is_the_second_parameter, this_is_the_third_parameter, this_is_the_forth_parameter, this_is_the_fifth_parameter, this_is_the_sixth_parameter): return this_is_the_first_parameter + this_is_the_second_parameter + this_is_the_third_parameter + \ this_is_the_forth_parameter + this_is_the_fifth_parameter + this_is_the_sixth_parameter (top_secret_func(param1=12345678, param2=12345678, param3=12345678, param4=12345678, param5=12345678).
什么是分布式事务? 简单的说,就是一次大操作由不同小操作组成,这些小操作分布在不同服务器上,分布式事务需要保证这些小操作要么全部成功,要么全部失败。
你上淘宝买东西,需要先扣钱,然后商品库存-1吧。但扣款和库存分别属于两个服务,这两个服务中间要经过网络、网关、主机等一系列中间层,万一任何一个地方出了问题,比如网络抖动、突发异常等待,都会导致不一致,比如扣款成功了,但是库存没-1,就会出现超卖的现象,而这就是分布式事务需要解决的问题。
分布式事务的应用场景? 1)电商系统中的下单扣库存
电商系统中,订单系统和库存系统是两个系统,一-次下单的操作由两个系统协同完成
2)金融系统中的银行卡充值
在金融系统中通过银行卡向平台充值需要通过银行系统和金融系统协同完成。
3)教育系统中下单选课业务
在线教育系统中,用户购买课程,下单支付成功后学生选课成功,此事务由订单系统和选课系统协同完成。
4) SNS系统的消息发送
在社交系统中发送站内消息同时发送手机短信,- -次消息发送由站内消息系统和手机通信系统协同完成。
CAP理论 如何进行分布式事务控制?CAP理论是分布式事务处理的理论基础
CAP理论是:分布式系统在设计时只能在一致性(Consistency)、可用性(Availability)、
分区容忍性(Partition Tolerance)中满足两种,无法兼顾三种。
一致性: 服务A、B、C三个结点都存储了用户数据, 三个结点的数据需要保持同一时刻数据一致性。 可用性: 服务A、B、C三个结点,其中一个结点宕机不影响整个集群对外提供服务,如果只有服务A结点,当服务A宕机整个系统将无法提供服务,增加服务B、C是为了保证系统的可用性。 分区容忍性: 分区容忍性就是允许系统通过网络协同工作,分区容忍性要解决由于网络分区导致数据的不完整及无法访问等问题。分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。 分布式系统能否兼顾C、A、P? 在保证分区容忍性的前提下一致性和可用性无法兼顾,如果要提高系统的可用性就要增加多个结点,如果要保证数据的一致性就要实现每个结点的数据一致,结点越多可用性越好,但是数据一致性越差。所以,在进行分布式系统设计时,同时满足“一致性”、“可用性”和“分区容忍性”三者是几乎不可能的。
CAP有哪些组合方式?
1、CA:放弃分区容忍性,加强一致性和可用性,关系数据库按照CA进行设计。
2、AP:放弃一致性,加强可用性和分区容忍性,追求最终一致性,很多NoSQL数据库按照AP进行设计。说明:这里放弃一致性是指放弃强一致性,强一致性就是写入成功立刻要查询出最新数据。追求最终一致性是指允许暂时的数据不一致,只要最终在用户接受的时间内数据 一致即可
3、CP:放弃可用性,加强一致性和分区容忍性,一些强一致性要求的系统按CP进行设计,比如跨行转账,一次转账请求要等待双方银行系统都完成整个事务才算完
成。 说明:由于网络问题的存在CP系统可能会出现待等待超时,如果没有处理超时问题则整理系统会出现阻塞
总结: 在分布式系统设计中AP的应用较多,即保证分区容忍性和可用性,牺牲数据的强一致性(写操作后立刻读取到最新数据),保证数据最终一致性。比如:订单退款,今日退款成功,明日账户到账,只要在预定的用户可以接受的时间内退款事务走完即可。
分布式事务解决方案
基于XA协议的2PC(二阶段提交)
XA是一个分布式事务协议。XA中大致分为两部分:事务管理器和本地资源管理器。其中本地资源管理器往往由数据库实现,比如Oracle、DB2这些商业数据库都实现了XA接口,而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚
2阶段提交是分布式事务传统解决方案,现在为止还广泛存在。当一个事务跨越多个节点时,为了保持事务ACID特性,需要引入一个协调者来统一掌控所有节点(称作参与者)的操作结果并最终指示这些节点是否要把操作结果进行真正的提交(比如将更新后的数据写入磁盘等等)。因此,二阶段提交的算法思路可以概括为:参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。
以开会为例
甲乙丙丁四人要组织一个会议,需要确定会议时间,不妨设甲是协调者,乙丙丁是参与者。
投票阶段
甲发邮件给乙丙丁,周二十点开会是否有时间;
丁回复有时间;
乙回复有时间;
丙迟迟不回复,此时对于这个活动,甲乙丙均处于阻塞状态,算法无法继续进行;
丙回复有时间(或者没有时间);
提交阶段
协调者甲将收集到的结果反馈给乙丙丁(什么时候反馈,以及反馈结果如何,在此例中取决
于丙的时间与决定);
乙收到;
丙收到;
丁收到;
缺点:不仅要锁住参与者的所有资源,而且要锁住协调者资源,开销大。一句话总
结就是:2PC效率很低,对高并发很不友好
3PC(三阶段提交)
与两阶段提交不同的是,三阶段提交有两个改动点。
1、引入超时机制。同时在协调者和参与者中都引入超时机制。2、在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与
节点的状态是一致的。也就是说,除了引入超时机制之外,3PC把2PC的准备阶段再
次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。
阶段一:CanCommit
事务询问 执行者向所有参与者发送CanCommit请求,等待所有参与者的响应
参与者反馈响应 参与者节点若认为自身可以完成事务,返回Yes;反之,返回No
阶段二:PreCommit
若所有参与者反馈的结果都是Yes响应,那么进行事务预提交
1. 创建Task
创建Task的方法有两种,一种是直接创建——new一个出来,一种是通过工厂创建。
//第一种创建方式,直接实例化 var task1 = new Task(() => { //TODO you code }); task1.Start(); 这是最简单的创建方法,可以看到其构造函数是一个Action。
//第二种创建方式,工厂创建 var task2 = Task.Factory.StartNew(() => { //TODO you code }); 这种方式通过静态工厂,创建以个Task并运行。
通过构造函数创建的task,必须手动Start,而通过工厂创建的Task直接就启动了。
2. Task的简略生命周期(状态):
Created:表示默认初始化任务,但是“工厂创建的”实例直接跳过。
WaitingToRun: 这种状态表示等待任务调度器分配线程给任务执行。
RanToCompletion:任务执行完毕。
3. Task的任务控制
Task最吸引人的地方就是他的任务控制了,你可以很好的控制task的执行顺序,让多个task有序的工作。
Task.Wait 就是等待任务执行完成
Task.WaitAll 就是等待所有的任务都执行完成
Task.WaitAny 就是等待任何一个任务完成就继续向下执行
Task.ContinueWith 就是在第一个Task完成后自动启动下一个Task,实现Task的延续
Task的取消 比如我们启动了一个task,出现异常或者用户点击取消等等,我们要取消这个任务,这时我们通过cancellation的tokens来取消一个Task。在很多Task的Body里面包含循环,我们可以在轮询的时候判断IsCancellationRequested属性是否为True,如果是True的话就return.
var tokenSource = new CancellationTokenSource(); var token = tokenSource.Token; var task = Task.Factory.StartNew(() => { for (var i = 0; i < 1000; i++) { System.