在《使用libevent实现简单http服务(一)》使用libevent实现了一个简单的http服务,但性能比较差,假设处理一个请求需要1ms,单个服务每秒最多也就能够处理1000个请求。为了提高单个服务的处理能力,可以通过多线程并发或多进程并发实现。
多线程源码如下:
#define MAX_THREAD_NUM 2
bool exit_flag = false;
void sigterm(int sig)
{
fprintf(stdout, "INFO recv term signal !\n");
exit_flag = true;
}
void http_server_thread(std::shared_ptr<simple_httpserver<simple_listener, simple_processor>> &ptr)
{
ptr->run();
}
int main(int argc, char **argv)
{
signal(SIGTERM, sigterm);
auto listener_ptr = std::make_shared<simple_listener>("0.0.0.0", 8080);
if (!listener_ptr->start()) {
fprintf(stderr, "ERROR failed to start listener !\n");
return -1;
}
std::vector<std::shared_ptr<simple_processor>> procssors;
std::vector<std::shared_ptr<simple_httpserver<simple_listener, simple_processor>>> httpservers;
std::vector<std::shared_ptr<std::thread>> threads;
int i = 0;
for (; i < MAX_THREAD_NUM; ++i) {
auto processor_ptr = std::make_shared<simple_processor>(i);
auto httpserver_ptr = std::make_shared<simple_httpserver<simple_listener, simple_processor>>(listener_ptr, processor_ptr);
if (!httpserver_ptr->start()) {
fprintf(stderr, "ERROR failed to start http server, index : %d !\n", i);
return -1;
}
procssors.push_back(processor_ptr);
httpservers.push_back(httpserver_ptr);
auto func = std::bind(http_server_thread, httpserver_ptr);
auto thread_ptr = std::make_shared<std::thread>(func);
threads.push_back(thread_ptr);
}
if (i == MAX_THREAD_NUM) {
while (!exit_flag) {
sleep(10);
}
}
fprintf(stdout, "INFO before server stop !\n");
for (auto &httpserver_ptr : httpservers)
httpserver_ptr->stop();
fprintf(stdout, "INFO after server stop !\n");
for (auto &thread : threads) {
if (thread->joinable()) {
thread->join();
}
}
fprintf(stdout, "INFO process exit !\n");
return 0;
}
多进程源码如下:
std::shared_ptr<simple_listener> g_listener_ptr; //监听对象
std::shared_ptr<simple_processor> g_processor_ptr; //请求处理对象
std::shared_ptr<simple_httpserver<simple_listener, simple_processor>> g_httpserver_ptr; //http服务对象
#define MAX_PROCESS_NUM 2
bool exit_flag = false;
pid_t sub_pids[MAX_PROCESS_NUM] = {0};
void sigterm_main(int sig)
{
fprintf(stdout, "INFO main process %d recv term signal !\n", getpid());
exit_flag = true;
}
void sigterm(int sig)
{
fprintf(stdout, "INFO sub process %d recv term signal !\n", getpid());
if (g_httpserver_ptr.get() != nullptr) {
fprintf(stdout, "INFO sub process %d httpserver before stop !\n", getpid());
g_httpserver_ptr->stop();
fprintf(stdout, "INFO sub process %d httpserver after stop !\n", getpid());
}
}
int main(int argc, char **argv)
{
signal(SIGTERM, sigterm_main);
g_listener_ptr = std::make_shared<simple_listener>("0.0.0.0", 8080);
if (!g_listener_ptr->start()) {
fprintf(stderr, "ERROR failed to open listener\n");
return -1;
}
bool main_process = true;
for (int i = 0; i < MAX_PROCESS_NUM; ++i) {
pid_t pid = fork();
if (pid == 0) { //子进程
signal(SIGTERM, sigterm);
main_process = false;
g_processor_ptr = std::make_shared<simple_processor>((int)getpid());
g_httpserver_ptr = std::make_shared<simple_httpserver<simple_listener, simple_processor>>(g_listener_ptr, g_processor_ptr);
if (!g_httpserver_ptr->start()) {
fprintf(stderr, "ERROR failed to start http server\n");
return -1;
}
g_httpserver_ptr->run();
printf("sub process %d leave\n", getpid());
return 0;
}
else { //记录子进程pid
sub_pids[i] = pid;
}
}
//主进程等待退出
if (main_process) {
while (!exit_flag) {
sleep(20);
}
for (int i = 0; i < MAX_PROCESS_NUM; ++i) {
kill(sub_pids[i], SIGTERM);
}
int status = 0;
wait(&status);
}
printf("process %d leave\n", getpid());
return 0;
}
以上两种方案都可以明显提高单机服务的处理能力。两种方案各有优缺点:对于多进程,安全性较高,但资源共享效率比较低,而多线程则相反。因此对于计算密集型的服务,适合使用多进程,而而对于以资源下载为主的服务,则适合使用多线程。