学习https://github.com/huoyu820125/SecondPaxos 自己编写网络版本

在学习过程将此代码的线程 锁等改成c++11  就不用包含那么多文件

主要更改如下

  1 // MyPaxos.cpp: 定义控制台应用程序的入口点。
  2 //
  3
  4 #include "stdafx.h"
  5 #include <iostream>
  6 #include <chrono>
  7 #include <mutex>
  8 #include <thread>
  9 #include "Acceptor.h"
 10 #include "Proposer.h"
 11
 12
 13 paxos::Proposer p[11];
 14 paxos::Acceptor a[11];
 15 int finishedCount = 0;
 16 std::mutex l[11];
 17
 18 std::mutex printlock;
 19
 20 void Proposer(int id) {
 21     paxos::Proposer &proposer = p[(int)id];
 22     paxos::PROPOSAL value = proposer.GetProposal();
 23     paxos::PROPOSAL lastValue;
 24
 25
 26     int acceptorId[11];
 27     int count = 0;
 28
 29     while (true) {
 30         value = proposer.GetProposal();//拿到提议
 31         printlock.lock();
 32         std::cout << "Proposer" << (int)id << "号开始(Propose阶段):提议=[编号:" << value.serialNum
 33             << ",提议:" << value.value << "]\n";
 34         printlock.unlock();
 35         count = 0;
 36         int i = 0;
 37
 38         for (i = 0; i < 11; i++)
 39         {
 40             /*
 41             * 发送消息到第i个acceptor
 42             * 经过一定时间达到acceptor,sleep(随机时间)模拟
 43             * acceptor处理消息,mAcceptors[i].Propose()
 44             * 回应proposer
 45             * 经过一定时间proposer收到回应,sleep(随机时间)模拟
 46             * proposer处理回应mProposer.proposed(ok, lastValue)
 47             */
 48             //经过随机时间,消息到达了mAcceptors[i]
 49             std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 100) );
 50             l[i].lock();
 51             bool ok = a[i].Propose(value.serialNum, lastValue);
 52             l[i].unlock();
 53             std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 100));
 54             //处理Propose回应
 55             if (!proposer.Proposed(ok, lastValue)) //重新开始Propose阶段
 56             {
 57                 std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 100));
 58                 //为了降低活锁,多等一会让别的proposer有机会完成自己的2阶段批准
 59                 break;
 60             }
 61             paxos::PROPOSAL curValue = proposer.GetProposal();//拿到提议
 62             if (curValue.value != value.value)//acceptor本次回应可能推荐了一个提议
 63             {
 64                 printlock.lock();
 65                 std::cout << "Proposer" << (int)id << "号修改了提议:提议=[编号:" <<
 66                     curValue.serialNum << ",提议:" << curValue.value << "]\n";
 67                 printlock.unlock();
 68             }
 69             acceptorId[count++] = i;//记录愿意投票的acceptor
 70             if (proposer.StartAccept())
 71             {
 72                 if (0 == rand() % 2) break;
 73             }
 74         }
 75         //检查有没有达到Accept开始条件,如果没有表示要重新开始Propose阶段
 76         if (!proposer.StartAccept()) continue;
 77         //开始Accept阶段
 78         //发送Accept消息到所有愿意投票的acceptor
 79         value = proposer.GetProposal();
 80         printlock.lock();
 81         std::cout << "Proposer" << (int)id << "号开始(Accept阶段):提议=[编号:" <<
 82             value.serialNum << ",提议:" << value.value << "]\n";
 83         printlock.unlock();
 84         for (i = 0; i < count; i++)
 85         {
 86             //发送accept消息到acceptor
 87             std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 100));//经过随机时间,accept消息到达acceptor
 88                                         //处理accept消息
 89             l[acceptorId[i]].lock();
 90             bool ok = a[acceptorId[i]].Accept(value);
 91             l[acceptorId[i]].unlock();
 92             std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 100));//经过随机时间,accept回应到达proposer
 93                                         //处理accept回应
 94             if (!proposer.Accepted(ok)) //重新开始Propose阶段
 95             {
 96                 std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 100));///为了降低活锁,多等一会让别的proposer有机会完成自己的2阶段批准
 97                 break;
 98             }
 99             if (proposer.IsAgree())//成功批准了提议
100             {
101                 printlock.lock();
102                 std::cout << "Proposer" << (int)id << "号批准了提议:最终提议 = [编号:" <<
103                     value.serialNum << ",提议:" << value.value << "]\n";
104                 printlock.unlock();
105                 return ;
106             }
107         }
108     }
109     return ;
110 }
111
112 int main()
113 {
114     int i = 0;
115     std::cout << "11个Proposer, 11个Acceptor准备进行Paxos\n"<<
116         "每个Proposer独立线程,Acceptor不需要线程\n"<<
117         "Proposer线程中等待随机时间:表示与Acceptor的通信时间\n"<<
118         "Proposer线程中调用Acceptor.Proposed()表示拿到了Propose请求结果\n"<<
119         "Proposer线程中调用Acceptor.Accepted()表示拿到了Accept请求结果\n"<<
120         "Proposer被批准后结束线程,其它线程继续投票最终,全部批准相同的值,达成一致。\n";
121
122     paxos::PROPOSAL value;
123     for (i = 0; i < 11; i++)
124     {
125         p[i].SetPlayerCount(11, 11);
126         value.serialNum = value.value = i + 1;
127         p[i].StartPropose(value);
128     }
129
130     std::thread t[11];
131     for (i = 0; i < 11; i++) {
132         t[i] = std::thread(Proposer, i);
133     }
134     for (i = 0; i < 11; i++) {
135         t[i].join();
136     }
137     while (true) {
138         std::this_thread::sleep_for(std::chrono::seconds(1));
139     }
140
141
142
143     return 0;
144 }

View Code

20180513添加

根据视频  paxos和分布式系统_1024x768_2.00M_h.264

添加自写代码 vs2017 boost1.65编译

方案1  单点接收多点提交 二段提交 抢占提交权

// Accepter.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <ctime>
#include <iostream>
#include <string>
#include <memory>
#include <mutex>
#include <thread>
#include <boost/asio.hpp>using boost::asio::ip::tcp;const int default_port = 9687;#pragma pack (1)
//提议数据结构
typedef struct PROPOSAL
{int    index;        //当前请求的阶段 int    epoch;        //流水号,1开始递增,保证全局唯一int    value;        //提议内容
}PROPOSAL;typedef struct ACCEPTSAL
{int    epoch;        //流水号,1开始递增,保证全局唯一int    value;        //提议内容
}ACCEPTSAL;
#pragma pack()enum INDEX {INIT_INDEX = 1,PREPARE_INDEX,ACCEPT_INDEX,FINISH_INDEX,ERROR_INDEX = -1,
};int current_index = PREPARE_INDEX;
ACCEPTSAL g_ServerRecord = {-1,-1 };
boost::asio::io_service io_service;
std::mutex g_mtx;
int acceptepoch = -1;
//==========================================================void HandlePropose(std::shared_ptr<tcp::socket> socket) {PROPOSAL buf = { -1,-1,-1 };ACCEPTSAL tmpAcpsal = { -1,-1 };try {while (1) {boost::asio::read(*socket, boost::asio::buffer(&buf, sizeof(buf)));{std::lock_guard<std::mutex> lock(g_mtx);//prepare阶段if (buf.index == PREPARE_INDEX) {if (g_ServerRecord.epoch <= buf.epoch && g_ServerRecord.value == -1) {//更新最新的prepare epochg_ServerRecord.epoch = buf.epoch;current_index = ACCEPT_INDEX;}}else if (buf.index == ACCEPT_INDEX && (-1 == g_ServerRecord.value)) {if ((buf.epoch >= g_ServerRecord.epoch)) {g_ServerRecord.value = buf.value;current_index = FINISH_INDEX;}}//拷贝accepter记录tmpAcpsal = g_ServerRecord;}//回复boost::asio::write(*socket, boost::asio::buffer(&tmpAcpsal, sizeof(tmpAcpsal)));}}catch (std::exception& e) {std::cerr << e.what() << std::endl;return;}
}int main()
{try {tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), default_port));for (;;) {std::shared_ptr<tcp::socket> psocket = std::make_shared<tcp::socket>(io_service);acceptor.accept(*psocket);std::thread t(HandlePropose,psocket);t.detach();}}catch (std::exception& e) {std::cerr << e.what() << std::endl;}return 0;
}

accepter

// Proposer.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <ctime>
#include <iostream>
#include <string>
#include <memory>
#include <mutex>
#include <thread>
#include <boost/asio.hpp>using boost::asio::ip::tcp;const std::string default_port = "9687";#pragma pack (1)
//提议数据结构
typedef struct PROPOSAL
{int    index;        //当前请求的阶段 int    epoch;        //流水号,1开始递增,保证全局唯一int    value;        //提议内容
}PROPOSAL;typedef struct ACCEPTSAL
{int    epoch;        //流水号,1开始递增,保证全局唯一int    value;        //提议内容
}ACCEPTSAL;
#pragma pack()enum INDEX {INIT_INDEX = 1,PREPARE_INDEX,ACCEPT_INDEX,FINISH_INDEX,ERROR_INDEX = -1,
};//========================================================int main()
{try {boost::asio::io_service io_service;tcp::resolver resolver(io_service);tcp::resolver::query query("127.0.0.1", default_port.c_str());tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);tcp::socket socket(io_service);boost::asio::connect(socket, endpoint_iterator);for (;;) {PROPOSAL pro = { PREPARE_INDEX ,1,99 };ACCEPTSAL tmpAcpsal = { -1,-1 };boost::system::error_code error;boost::asio::write(socket, boost::asio::buffer(&pro,sizeof(pro)), error);size_t len = socket.read_some(boost::asio::buffer(&tmpAcpsal,sizeof(tmpAcpsal)), error);if (error == boost::asio::error::eof)break; // Connection closed cleanly by peer.else if (error)throw boost::system::system_error(error); // Some other error.if (tmpAcpsal.epoch == pro.epoch) {pro.index = ACCEPT_INDEX;boost::asio::write(socket, boost::asio::buffer(&pro, sizeof(pro)), error);size_t len = socket.read_some(boost::asio::buffer(&tmpAcpsal, sizeof(tmpAcpsal)), error);}if (tmpAcpsal.value != -1) {std::cout << " value is  " << tmpAcpsal.value << std::endl;system("pause");return 1;}else {std::cerr << " value is  " << tmpAcpsal.value << "  . Error !!!" << std::endl;system("pause");return 1;}}}catch (std::exception& e) {std::cerr << e.what() << std::endl;}system("pause");return 0;
}

propose

缺点 若抢占的propose 出现故障 则无法释放锁

方案2 单点接受多点提交 二段提交 根据epoch抢占提交权 若获取提交权的proposer出现故障 将会被拥有更高epoch的propose替代

// Accepter.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <ctime>
#include <iostream>
#include <string>
#include <memory>
#include <mutex>
#include <thread>
#include <boost/asio.hpp>using boost::asio::ip::tcp;const int default_port = 9687;#pragma pack (1)
//提议数据结构
typedef struct PROPOSAL
{int    index;        //当前请求的阶段 int    epoch;        //流水号,1开始递增,保证全局唯一int    value;        //提议内容
}PROPOSAL;typedef struct ACCEPTSAL
{int    epoch;        //流水号,1开始递增,保证全局唯一int    value;        //提议内容
}ACCEPTSAL;
#pragma pack()enum INDEX {INIT_INDEX = 1,PREPARE_INDEX,ACCEPT_INDEX,FINISH_INDEX,ERROR_INDEX = -1,
};int current_index = PREPARE_INDEX;
ACCEPTSAL g_ServerRecord = {-1,-1 };
boost::asio::io_service io_service;
std::mutex g_mtx;
int acceptepoch = -1;
//==========================================================void HandlePropose(std::shared_ptr<tcp::socket> socket) {PROPOSAL buf = { -1,-1,-1 };ACCEPTSAL tmpAcpsal = { -1,-1 };try {while (1) {boost::asio::read(*socket, boost::asio::buffer(&buf, sizeof(buf)));{std::lock_guard<std::mutex> lock(g_mtx);std::cout << "recv " << "index = " << buf.index << ". epoch = " << buf.epoch << ". value = " << buf.value << std::endl;}{std::lock_guard<std::mutex> lock(g_mtx);//prepare阶段if (buf.index == PREPARE_INDEX) {if (g_ServerRecord.epoch <= buf.epoch && g_ServerRecord.value == -1) {std::cout << "Prepare index" << std::endl;std::cout << "Prepare recv " << "index = " << buf.index << ". epoch = " << buf.epoch << ". value = " << buf.value << std::endl;//更新最新的prepare epochg_ServerRecord.epoch = buf.epoch;current_index = ACCEPT_INDEX;}}else if (buf.index == ACCEPT_INDEX && (-1 == g_ServerRecord.value)) {if ((buf.epoch >= g_ServerRecord.epoch)) {std::cout << "Accept index, epoch =" << buf.epoch << ".value = "<< buf.value << std::endl;g_ServerRecord.epoch = buf.epoch;g_ServerRecord.value = buf.value;current_index = FINISH_INDEX;}}//拷贝accepter记录tmpAcpsal = g_ServerRecord;}//回复
            {std::lock_guard<std::mutex> lock(g_mtx);std::cout << "reply epoch = " << tmpAcpsal.epoch << ". value = " << tmpAcpsal.value << std::endl;}boost::asio::write(*socket, boost::asio::buffer(&tmpAcpsal, sizeof(tmpAcpsal)));}}catch (std::exception& e) {//std::cerr << e.what() << std::endl;return;}
}int main()
{try {tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), default_port));for (;;) {std::shared_ptr<tcp::socket> psocket = std::make_shared<tcp::socket>(io_service);acceptor.accept(*psocket);std::thread t(HandlePropose,psocket);t.detach();}}catch (std::exception& e) {std::cerr << e.what() << std::endl;}return 0;
}

accepter

// Proposer.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <ctime>
#include <iostream>
#include <string>
#include <memory>
#include <mutex>
#include <random>
#include <thread>
#include <boost/asio.hpp>using boost::asio::ip::tcp;const std::string default_port = "9687";#pragma pack (1)
//提议数据结构
typedef struct PROPOSAL
{int    index;        //当前请求的阶段 int    epoch;        //流水号,1开始递增,保证全局唯一int    value;        //提议内容
}PROPOSAL;typedef struct ACCEPTSAL
{int    epoch;        //流水号,1开始递增,保证全局唯一int    value;        //提议内容
}ACCEPTSAL;
#pragma pack()enum INDEX {INIT_INDEX = 1,PREPARE_INDEX,ACCEPT_INDEX,FINISH_INDEX,ERROR_INDEX = -1,
};
//========================================================
boost::asio::io_service io_service;unsigned GetRand()
{static std::default_random_engine e;static std::uniform_int_distribution<unsigned> u(0, 1000);return u(e);
}void ProposeThreadFunc(int id) {try {tcp::resolver resolver(io_service);tcp::resolver::query query("127.0.0.1", default_port.c_str());tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);tcp::socket socket(io_service);boost::asio::connect(socket, endpoint_iterator);int epoch = id+1;for (;;) {PROPOSAL pro = { PREPARE_INDEX ,epoch +1,id +1 };ACCEPTSAL tmpAcpsal = { -1,-1 };boost::system::error_code error;boost::asio::write(socket, boost::asio::buffer(&pro, sizeof(pro)), error);size_t len = socket.read_some(boost::asio::buffer(&tmpAcpsal, sizeof(tmpAcpsal)), error);if (error == boost::asio::error::eof)break; // Connection closed cleanly by peer.else if (error)throw boost::system::system_error(error); // Some other error.if (tmpAcpsal.epoch == pro.epoch) {pro.index = ACCEPT_INDEX;std::chrono::milliseconds dura(GetRand());std::this_thread::sleep_for(dura);boost::asio::write(socket, boost::asio::buffer(&pro, sizeof(pro)), error);size_t len = socket.read_some(boost::asio::buffer(&tmpAcpsal, sizeof(tmpAcpsal)), error);}if (tmpAcpsal.epoch > epoch) {int i = tmpAcpsal.epoch%11;int loopcount = tmpAcpsal.epoch / 11;epoch = loopcount * 11 + 11 + id + 1;if(id == 2)std::cout << "epoch = " << epoch << std::endl;}if (tmpAcpsal.value != -1) {std::cout << " value is  " << tmpAcpsal.value << std::endl;break ;}std::chrono::milliseconds dura(GetRand());std::this_thread::sleep_for(dura);}}catch (std::exception& e) {std::cerr << e.what() << std::endl;}
}int main()
{std::thread t[11];for (int i = 0; i < 11; i++) {t[i] = std::thread(ProposeThreadFunc,i);}for (int i = 0; i < 11; i++) {t[i].join();}system("pause");return 0;
}

propose

运行代码 添加随机参数 最后提交接受的数值 实现随机化

运行第一次 最后接受数值为6

运行第二次 最后接受数值为2

accept扩展多点 匹配客户端待完成

// accepters.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <ctime>
#include <iostream>
#include <string>
#include <memory>
#include <mutex>
#include <thread>
#include <boost/asio.hpp>using boost::asio::ip::tcp;const int default_port = 9687;#pragma pack (1)
//提议数据结构
typedef struct PROPOSAL
{int    index;        //当前请求的阶段 int    epoch;        //流水号,1开始递增,保证全局唯一int    value;        //提议内容
}PROPOSAL;typedef struct ACCEPTSAL
{int    epoch;        //流水号,1开始递增,保证全局唯一int    value;        //提议内容
}ACCEPTSAL;
#pragma pack()enum INDEX {INIT_INDEX = 1,PREPARE_INDEX,ACCEPT_INDEX,FINISH_INDEX,ERROR_INDEX = -1,
};
//=======================================================
//多个accepter记录
boost::asio::io_service io_service;int current_index[11];// = PREPARE_INDEX;
ACCEPTSAL g_ServerRecord[11];// = { -1,-1 };
std::mutex g_mtx[11];
std::mutex g_print_mtx;
int acceptepoch[11];// = -1;//=====================================================
void HandlePropose(std::shared_ptr<tcp::socket> socket,int id) {PROPOSAL buf = { -1,-1,-1 };ACCEPTSAL tmpAcpsal = { -1,-1 };try {while (1) {boost::asio::read(*socket, boost::asio::buffer(&buf, sizeof(buf)));{std::lock_guard<std::mutex> lock(g_mtx[id]);std::lock_guard<std::mutex> printLock(g_print_mtx);std::cout << "recv " << "index = " << buf.index << ". epoch = " << buf.epoch << ". value = " << buf.value << std::endl;}{std::lock_guard<std::mutex> lock(g_mtx[id]);//prepare阶段if (buf.index == PREPARE_INDEX) {if (g_ServerRecord[id].epoch <= buf.epoch && g_ServerRecord[id].value == -1) {{std::lock_guard<std::mutex> printLock(g_print_mtx);std::cout << "Prepare index" << std::endl;std::cout << "Prepare recv " << "index = " << buf.index << ". epoch = " << buf.epoch << ". value = " << buf.value << std::endl;}//更新最新的prepare epochg_ServerRecord[id].epoch = buf.epoch;current_index[id] = ACCEPT_INDEX;}}else if (buf.index == ACCEPT_INDEX && (-1 == g_ServerRecord[id].value)) {if ((buf.epoch >= g_ServerRecord[id].epoch)) {{std::lock_guard<std::mutex> printLock(g_print_mtx);std::cout << "Accept index, epoch =" << buf.epoch << ".value = " << buf.value << std::endl;}g_ServerRecord[id].epoch = buf.epoch;g_ServerRecord[id].value = buf.value;current_index[id] = FINISH_INDEX;}}//拷贝accepter记录tmpAcpsal = g_ServerRecord[id];}//回复
            {std::lock_guard<std::mutex> lock(g_mtx[id]);{std::lock_guard<std::mutex> printLock(g_print_mtx);std::cout << "reply epoch = " << tmpAcpsal.epoch << ". value = " << tmpAcpsal.value << std::endl;}}boost::asio::write(*socket, boost::asio::buffer(&tmpAcpsal, sizeof(tmpAcpsal)));}}catch (std::exception& e) {//std::cerr << e.what() << std::endl;return;}
}void AcceptThreadFunc(int id) {try {tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), default_port+id));for (;;) {std::shared_ptr<tcp::socket> psocket = std::make_shared<tcp::socket>(io_service);acceptor.accept(*psocket);std::thread t(HandlePropose, psocket,id);t.detach();}}catch (std::exception& e) {std::cerr << e.what() << std::endl;}
}void init() {for (int i = 0; i < 11; i++) {current_index[i] = PREPARE_INDEX;g_ServerRecord[i].epoch = -1;g_ServerRecord[i].value = -1;}
}int main()
{init();std::thread t[11];for (int i = 0; i < 11; i++) {t[i] = std::thread(AcceptThreadFunc,i);}for (int i = 0; i < 11; i++) {t[i].join();}return 0;
}

View Code

转载于:https://www.cnblogs.com/itdef/p/9002220.html

paxos 练手 推进中相关推荐

  1. c# 火狐浏览器怎么嵌入窗体中_「C#上位机必看」你们想要的练手项目来了

    最近有越来越多做电气的小伙伴开始学习C#来做上位机开发,很多人在学习一段时间后,都有这种感觉,似乎学到了很多知识,但是不知道怎么应用,因此我找了一个真实的上位机小项目,让大家来练练手.这篇文章主要对这 ...

  2. Python练手小程序—统计英文文件中单词出现的的个数

    在GitHub上发现一些很有意思的项目,由于本人作为Python的初学者,编程代码能力相对薄弱,为了加强Python的学习,特此利用前辈们的学习知识成果,自己去亲自实现. 一周没有更新了,主要还是自己 ...

  3. 一个适合于Python 初学者的入门练手项目

    随着人工智能的兴起,国内掀起了一股Python学习热潮,入门级编程语言,大多选择Python,有经验的程序员,也开始学习Python,正所谓是人生苦短,我用Python 有个Python入门练手项目, ...

  4. python新手项目-推荐:一个适合于Python新手的入门练手项目

    原标题:推荐:一个适合于Python新手的入门练手项目 随着人工智能的兴起,国内掀起了一股Python学习热潮,入门级编程语言,大多选择Python,有经验的程序员,也开始学习Python,正所谓是人 ...

  5. python新手小项目-推荐:一个适合于Python新手的入门练手项目

    随着人工智能的兴起,国内掀起了一股Python学习热潮,入门级编程语言,大多选择Python,有经验的程序员,也开始学习Python,正所谓是人生苦短,我用Python 有个Python入门练手项目, ...

  6. python新手程序_推荐:一个适合于Python新手的入门练手项目

    随着人工智能的兴起,国内掀起了一股Python学习热潮,入门级编程语言,大多选择Python,有经验的程序员,也开始学习Python,正所谓是人生苦短,我用Python 有个Python入门练手项目, ...

  7. python新手入门项目推荐_推荐:一个适合于Python新手的入门练手项目

    随着人工智能的兴起,国内掀起了一股Python学习热潮,入门级编程语言,大多选择Python,有经验的程序员,也开始学习Python,正所谓是人生苦短,我用Python 有个Python入门练手项目, ...

  8. 适合新手入门的8个python项目_推荐:一个适合于Python新手的入门练手项目

    随着人工智能的兴起,国内掀起了一股Python学习热潮,入门级编程语言,大多选择Python,有经验的程序员,也开始学习Python,正所谓是人生苦短,我用Python 有个Python入门练手项目, ...

  9. 一个适合于Python初学者的入门练手项目

    随着人工智能的兴起,国内掀起了一股Python学习热潮,入门级编程语言,大多选择Python,有经验的程序员,也开始学习Python,正所谓是人生苦短,我用Python 有个Python入门练手项目, ...

最新文章

  1. 英语是缺乏AOP的语言,汉语是具备AOP的语言。
  2. java中的IO详解(上)
  3. 【 HDU1043-经典BFS+康拓展开 八数码】 (待更)
  4. 23种设计模式C++源码与UML实现--工厂模式
  5. python程序设计案例课堂第二篇_Python程序设计案例课堂第二篇核心技术第十章图形用户界面...
  6. LiveVideoStack线上交流分享 ( 五 ) —— 在线教育音视频技术探索与应用
  7. iPhone清理喇叭灰尘_厉害了,iPhone 专用的网购商品历史最低价查询工具
  8. linux io分析工具,io性能分析工具-iostat
  9. 学习C++项目—— 搭建多进程网络服务框架,增加业务和日志,心跳机制
  10. 【生信进阶练习1000days】day13-GEOquery
  11. 我是如何入门机器学习的呢
  12. yuv420p 详解_YUV格式详解,图文详解YUV420数据格式
  13. 数字金额转化为中文大写
  14. self._handle = _dlopen(self._name, mode) OSError: [WinError 126] 找不到指定的模块
  15. Linux各目录及每个目录的详细介绍
  16. springboot中如何使用RedisTemplate存储实体对象
  17. 分形几何python代码_Python教程之绘制Mandelbrot集合
  18. 如何破解网络密码?(2种方法)
  19. 云计算:优势与未来趋势
  20. PCL(Point Cloud Library)的第三方库简介(boost,eigen,flann,vtk,qhull)

热门文章

  1. Web前端开发:SQL Jsp小项目(一)
  2. 转:ubuntu或linux网卡配置/etc/network/interfaces
  3. C++ 工程实践(2):不要重载全局 ::operator new()
  4. 地平线开源轻量级、有效可变组卷积的人脸识别网络VarGFaceNet
  5. 深度学习超分辨率最新综述:一文道尽技术分类与效果评测
  6. html中文案竖排怎么写,做了这个活动,感觉自己成了垂直排版css大师(文字竖排)...
  7. 大数据分析必须要会的数据预处理操作(一)!!!
  8. numpy.random随机数模块常用函数总结
  9. 从大数据到深度学习,这些年度开源“新秀”你可用过?
  10. mscoco数据集_caffe详解之数据层