1. 程式人生 > >處理大併發之四 libevent demo詳細分析(對比epoll)

處理大併發之四 libevent demo詳細分析(對比epoll)

處理大併發之四 libevent demo詳細分析(對比epoll

libevent預設情況下是單執行緒,每個執行緒有且僅有一個event_base,對應一個struct event_base結構體,以及賦予其上的事件管理器,用來安排託管給它的一系列的事件。

當有一個事件發生的時候,event_base會在合適的時間去呼叫繫結在這個事件上的函式,直到這個函式執行完成,然後在返回安排其他事件。需要注意的是:合適的時間並不是立即。

例如:

[cpp] view plain copy print?
  1. struct event_base *base;  
  2. base = event_base_new();//初始化libevent
struct event_base *base;
base = event_base_new();//初始化libevent

event_base_new對比epoll,可以理解為epoll裡的epoll_create。

event_base內部有一個迴圈,迴圈阻塞在epoll呼叫上,當有一個事件發生的時候,才會去處理這個事件。其中,這個事件是被繫結在event_base上面的,每一個事件就會對應一個struct event,可以是監聽的fd。 

其中struct event 使用event_new 來建立和繫結,使用event_add來啟用,例如:

[cpp] view plain copy
print?
  1. struct event *listener_event;  
  2. listener_event = event_new(base, listener, EV_READ|EV_PERSIST, do_accept, (void*)base);  
struct event *listener_event;
listener_event = event_new(base, listener, EV_READ|EV_PERSIST, do_accept, (void*)base);

引數說明:

base:event_base型別,event_base_new的返回值

listener:監聽的fd,listen的fd

EV_READ|EV_PERSIST事件的型別及屬性

do_accept:繫結的回撥函式

(void*)base:給回撥函式的引數

event_add(listener_event, NULL);

對比epoll:

event_new相當於epoll中的epoll_wait,其中的epoll裡的while迴圈,在libevent裡使用event_base_dispatch

event_add相當於epoll中的epoll_ctl,引數是EPOLL_CTL_ADD,新增事件。

注:libevent支援的事件及屬性包括(使用bitfield實現,所以要用 | 來讓它們合體)EV_TIMEOUT超時EV_READ只要網路緩衝中還有資料,回撥函式就會被觸發EV_WRITE只要塞給網路緩衝的資料被寫完,回撥函式就會被觸發EV_SIGNAL: POSIX訊號量EV_PERSIST不指定這個屬性的話,回撥函式被觸發後事件會被刪除EV_ET: Edge-Trigger邊緣觸發,相當於EPOLLET模式

事件建立新增之後,就可以處理髮生的事件了,相當於epoll裡的epoll_wait,libevent裡使用event_base_dispatch啟動event_base迴圈,直到不再有需要關注的事件。

有了上面的分析,結合之前做的epoll服務端程式,對於一個伺服器程式,流程基本是這樣的:

1. 建立socketbindlisten,設定為非阻塞模式

2. 建立一個event_base,即

[cpp] view plain copy print?
  1. struct event_base *  event_base_new(void)  
struct event_base *  event_base_new(void)

3. 建立一個event,將該socket託管給event_base,指定要監聽的事件型別,並繫結上相應的回撥函式(及需要給它的引數)

[cpp] view plain copy print?
  1. struct event *  event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, shortvoid *), void *arg)  
struct event *  event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, short, void *), void *arg)

4. 啟用該事件,即

[cpp] view plain copy print?
  1. int  event_add(struct event *ev, conststruct timeval *tv)  
int  event_add(struct event *ev, const struct timeval *tv)

5.  進入事件迴圈,即

[cpp] view plain copy print?
  1. int  event_base_dispatch(struct event_base *event_base)  
int  event_base_dispatch(struct event_base *event_base)

首先來翻譯下例子上面的一段話:

對於select函式來說,不同的作業系統有不同的代替函式,它包括:poll,epoll,kqueue,evport/dev/poll。這些函式的效能都比select要好,其中epollIO中新增,刪除,通知socket準備好方面效能複雜度為O(1)

不幸的是,沒有一個有效的介面是一個普遍存在的標準,Linux下有epollBSDSkqueueSolaris 有evport/dev/poll,等等。沒有任何一個作業系統有它們中所有的,所以如果你想做一個輕便的高效能的非同步應用程式,你就需要把這些介面抽象的封裝起來,並且無論哪一個系統使用它都是最高效的。

這對於你來說就是最低階的libevent API,它提供了統一的介面取代了select,當它在計算機上執行的時候,使用了最有效的版本。

這裡是ROT13伺服器的另外一個版本,這次,他使用了libevent代替了select。這意味著我們不再使用fd_sets,取而代之的使用event_base新增和刪除事件,它可能在selectpollepollkqueue等中執行。

程式碼分析:

這是一個服務端的程式,可以處理客戶端大併發的連線,當收到客戶端的連線後,將收到的資料做了一個變換,如果是 ’a’-‘m’之間的字元,將其增加13,如果是 ’n’-‘z’之間的字元,將其減少13,其他字元不變,然後將轉換後的資料傳送給客戶端。

例如:客戶端傳送:Client 0 send  Message!

服務端會回覆:Pyvrag 0 fraq  Zrffntr!

在這個程式碼中沒有使用bufferevent這個強大的東西,在一個結構體中自己管理了一個緩衝區。結構體為:

[cpp] view plain copy print?
  1. struct fd_state {  
  2.     char buffer[MAX_LINE];//緩衝區的大小
  3.     size_t buffer_used;//接收到已經使用的buffer大小,每次將接收到的資料位元組數相加,當傳送的位元組數累計相加和buffer_used都相等時候,將它們都置為1
  4.     size_t n_written;//傳送的累加位元組數
  5.     size_t write_upto;//相當於一個臨時變數,當遇到換行符的時,將其收到的位元組數(換行符除外)賦給該值,當檢測到寫事件的時候,用已經發送的位元組數和該數值做比較,若收到的位元組總數小於該值,則傳送資料,等於該值,將結構體中3個位元組數統計變數都置為1,為什麼會置為1呢,因為有一個換行符吧。
  6.     struct event *read_event;  
  7.     struct event *write_event;  
  8. };  
struct fd_state {
    char buffer[MAX_LINE];//緩衝區的大小
    size_t buffer_used;//接收到已經使用的buffer大小,每次將接收到的資料位元組數相加,當傳送的位元組數累計相加和buffer_used都相等時候,將它們都置為1

    size_t n_written;//傳送的累加位元組數
    size_t write_upto;//相當於一個臨時變數,當遇到換行符的時,將其收到的位元組數(換行符除外)賦給該值,當檢測到寫事件的時候,用已經發送的位元組數和該數值做比較,若收到的位元組總數小於該值,則傳送資料,等於該值,將結構體中3個位元組數統計變數都置為1,為什麼會置為1呢,因為有一個換行符吧。

    struct event *read_event;
    struct event *write_event;
};

程式碼中自己管理了一個緩衝區,用於存放接收到的資料,傳送的資料將其轉換後也放入該緩衝區中,程式碼晦澀難懂,我也是經過打日誌分析後,才明白點,這個緩衝區自己還得控制好。但是libevent 2已經提供了一個神器bufferevent,我們在使用的過程中最好不要自己管理這個緩衝區,之所以分析這個程式碼,是為了熟悉libevent 做服務端程式的流程及原理。

下面是程式碼,加有部分註釋和日誌:

程式碼:lowlevel_libevent_server.c 

[cpp] view plain copy print?
  1. //說明,為了使我們的程式碼相容win32網路API,我們使用evutil_socket_t代替int,使用evutil_make_socket_nonblocking代替fcntl
  2. /* For sockaddr_in */
  3. #include <netinet/in.h>
  4. /* For socket functions */
  5. #include <sys/socket.h>
  6. /* For fcntl */
  7. #include <fcntl.h>
  8. #include <event2/event.h>
  9. #include <assert.h>
  10. #include <unistd.h>
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <errno.h>
  15. #define MAX_LINE 80
  16. void do_read(evutil_socket_t fd, short events, void *arg);  
  17. void do_write(evutil_socket_t fd, short events, void *arg);  
  18. char rot13_char(char c)  
  19. {  
  20.     /* We don't want to use isalpha here; setting the locale would change 
  21.      * which characters are considered alphabetical. */
  22.     if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M'))  
  23.         return c + 13;  
  24.     elseif ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z'))  
  25.         return c - 13;  
  26.     else
  27.         return c;  
  28. }  
  29. struct fd_state {  
  30.     char buffer[MAX_LINE];  
  31.     size_t buffer_used;  
  32.     size_t n_written;  
  33.     size_t write_upto;  
  34.     struct event *read_event;  
  35.     struct event *write_event;  
  36. };  
  37. struct fd_state * alloc_fd_state(struct event_base *base, evutil_socket_t fd)  
  38. {  
  39.     struct fd_state *state = malloc(sizeof(struct fd_state));  
  40.     if (!state)  
  41.         return NULL;  
  42.     state->read_event = event_new(base, fd, EV_READ|EV_PERSIST, do_read, state);  
  43.     if (!state->read_event)  
  44.     {  
  45.         free(state);  
  46.         return NULL;  
  47.     }  
  48.     state->write_event = event_new(base, fd, EV_WRITE|EV_PERSIST, do_write, state);  
  49.     if (!state->write_event)  
  50.     {  
  51.         event_free(state->read_event);  
  52.         free(state);  
  53.         return NULL;  
  54.     }  
  55.     state->buffer_used = state->n_written = state->write_upto = 0;  
  56.     assert(state->write_event);  
  57.     return state;  
  58. }  
  59. void free_fd_state(struct fd_state *state)  
  60. {  
  61.     event_free(state->read_event);  
  62.     event_free(state->write_event);  
  63.     free(state);  
  64. }  
  65. void do_read(evutil_socket_t fd, short events, void *arg)  
  66. {  
  67.     struct fd_state *state = arg;  
  68.     char buf[20];  
  69.     int i;  
  70.     ssize_t result;  
  71.     printf("\ncome in do_read: fd: %d, state->buffer_used: %d, sizeof(state->buffer): %d\n", fd, state->buffer_used, size  
  72. of(state->buffer));  
  73.     while (1)  
  74.     {  
  75.         assert(state->write_event);  
  76.         result = recv(fd, buf, sizeof(buf), 0);  
  77.         if (result <= 0)  
  78.             break;  
  79.         printf("recv once, fd: %d, recv size: %d, recv buff: %s\n", fd, result, buf);  
  80.         for (i=0; i < result; ++i)  
  81.         {  
  82.             if (state->buffer_used < sizeof(state->buffer))//如果讀事件的緩衝區還未滿,將收到的資料做轉換
  83.                 state->buffer[state->buffer_used++] = rot13_char(buf[i]);  
  84. //              state->buffer[state->buffer_used++] = buf[i];//接收什麼傳送什麼,不經過轉換,測試用
  85.             if (buf[i] == '\n'//如果遇到換行,新增寫事件,並設定寫事件的大小
  86.             {  
  87.                 assert(state->write_event);  
  88.                 event_add(state->write_event, NULL);  
  89.                 state->write_upto = state->buffer_used;  
  90.                 printf("遇到換行符,state->write_upto: %d, state->buffer_used: %d\n",state->write_upto, state->buffer_use  
  91. d);  
  92.             }  
  93.         }  
  94.         printf("recv once, state->buffer_used: %d\n", state->buffer_used);  
  95. }  
  96.     //判斷最後一次接收的位元組數
  97.     if (result == 0)  
  98.     {  
  99.         free_fd_state(state);  
  100.     }  
  101.     elseif (result < 0)  
  102.     {  
  103.         if (errno == EAGAIN) // XXXX use evutil macro
  104.             return;  
  105.         perror("recv");  
  106.         free_fd_state(state);  
  107.     }  
  108. }  
  109. void do_write(evutil_socket_t fd, short events, void *arg)  
  110. {  
  111.     struct fd_state *state = arg;  
  112.     printf("\ncome in do_write, fd: %d, state->n_written: %d, state->write_upto: %d\n",fd, state->n_written, state->write  
  113. _upto);  
  114.     while (state->n_written < state->write_upto)  
  115.     {  
  116.         ssize_t result = send(fd, state->buffer + state->n_written, state->write_upto - state->n_written, 0);  
  117.         if (result < 0) {  
  118.             if (errno == EAGAIN) // XXX use evutil macro
  119.                 return;  
  120.             free_fd_state(state);  
  121.             return;  
  122.         }  
  123.         assert(result != 0);  
  124.         state->n_written += result;  
  125.         printf("send fd: %d, send size: %d, state->n_written: %d\n", fd, result, state->n_written);  
  126.     }  
  127.     if (state->n_written == state->buffer_used)  
  128.     {  
  129.         printf("state->n_written == state->buffer_used: %d\n", state->n_written);  
  130.         state->n_written = state->write_upto = state->buffer_used = 1;  
  131.         printf("state->n_written = state->write_upto = state->buffer_used = 1\n");  
  132.     }  
  133.     event_del(state->write_event);  
  134. }  
  135. void do_accept(evutil_socket_t listener, short event, void *arg)  
  136. {  
  137.     struct event_base *base = arg;  
  138.     struct sockaddr_storage ss;  
  139.     socklen_t slen = sizeof(ss);  
  140.     int fd = accept(listener, (struct sockaddr*)&ss, &slen);  
  141.     if (fd < 0)  
  142.     { // XXXX eagain??
  143.         perror("accept");  
  144.     }  
  145.     elseif (fd > FD_SETSIZE)  
  146.     {  
  147.         close(fd); // XXX replace all closes with EVUTIL_CLOSESOCKET */
  148.     }  
  149.     else
  150.     {  
  151.         struct fd_state *state;  
  152.         evutil_make_socket_nonblocking(fd);  
  153.         state = alloc_fd_state(base, fd);  
  154.         assert(state); /*XXX err*/
  155.         assert(state->write_event);  
  156.         event_add(state->read_event, NULL);  
  157.     }  
  158. }  
  159. void run(void)  
  160. {  
  161.     evutil_socket_t listener;  
  162.     struct sockaddr_in sin;  
  163.     struct event_base *base;  
  164.     struct event *listener_event;  
  165.     base = event_base_new();//初始化libevent
  166.     if (!base)  
  167.         return/*XXXerr*/
  168.     sin.sin_family = AF_INET;  
  169.     sin.sin_addr.s_addr = 0;//本機
  170.     sin.sin_port = htons(8000);  
  171.     listener = socket(AF_INET, SOCK_STREAM, 0);  
  172.     evutil_make_socket_nonblocking(listener);  
  173. #ifndef WIN32
  174.     {  
  175.         int one = 1;  
  176.         setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));  
  177.     }  
  178. #endif
  179.     if (bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < 0)  
  180.     {  
  181.         perror("bind");  
  182.         return;  
  183.   }  
  184.       if (listen(listener, 16)<0)  
  185.       {  
  186.           perror("listen");  
  187.           return;  
  188.       }  
  189.       listener_event = event_new(base, listener, EV_READ|EV_PERSIST, do_accept, (void*)base);  
  190.       /*XXX check it */
  191.       event_add(listener_event, NULL);  
  192.       event_base_dispatch(base);  
  193.   }  
  194.   int main(int c, char **v)  
  195.   {  
  196.   //    setvbuf(stdout, NULL, _IONBF, 0);
  197.       run();  
  198.       return 0;  
  199.   }  
//說明,為了使我們的程式碼相容win32網路API,我們使用evutil_socket_t代替int,使用evutil_make_socket_nonblocking代替fcntl

/* For sockaddr_in */
#include <netinet/in.h>
/* For socket functions */
#include <sys/socket.h>
/* For fcntl */
#include <fcntl.h>

#include <event2/event.h>

#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

#define MAX_LINE 80

void do_read(evutil_socket_t fd, short events, void *arg);
void do_write(evutil_socket_t fd, short events, void *arg);

char rot13_char(char c)
{
    /* We don't want to use isalpha here; setting the locale would change
     * which characters are considered alphabetical. */
    if ((c >= 'a' && c <= 'm') || (c >= 'A' && c <= 'M'))
        return c + 13;
    else if ((c >= 'n' && c <= 'z') || (c >= 'N' && c <= 'Z'))
        return c - 13;
    else
        return c;
}

struct fd_state {
    char buffer[MAX_LINE];
    size_t buffer_used;

    size_t n_written;
    size_t write_upto;

    struct event *read_event;
    struct event *write_event;
};

struct fd_state * alloc_fd_state(struct event_base *base, evutil_socket_t fd)
{
    struct fd_state *state = malloc(sizeof(struct fd_state));
    if (!state)
        return NULL;

    state->read_event = event_new(base, fd, EV_READ|EV_PERSIST, do_read, state);
    if (!state->read_event)
    {
        free(state);
        return NULL;
    }

    state->write_event = event_new(base, fd, EV_WRITE|EV_PERSIST, do_write, state);
    if (!state->write_event)
    {
        event_free(state->read_event);
        free(state);
        return NULL;
    }

    state->buffer_used = state->n_written = state->write_upto = 0;

    assert(state->write_event);
    return state;
}

void free_fd_state(struct fd_state *state)
{
    event_free(state->read_event);
    event_free(state->write_event);
    free(state);
}

void do_read(evutil_socket_t fd, short events, void *arg)
{
    struct fd_state *state = arg;
    char buf[20];
    int i;
    ssize_t result;
    printf("\ncome in do_read: fd: %d, state->buffer_used: %d, sizeof(state->buffer): %d\n", fd, state->buffer_used, size
of(state->buffer));
    while (1)
    {
        assert(state->write_event);
        result = recv(fd, buf, sizeof(buf), 0);
        if (result <= 0)
            break;
        printf("recv once, fd: %d, recv size: %d, recv buff: %s\n", fd, result, buf);

        for (i=0; i < result; ++i)
        {
            if (state->buffer_used < sizeof(state->buffer))//如果讀事件的緩衝區還未滿,將收到的資料做轉換
                state->buffer[state->buffer_used++] = rot13_char(buf[i]);
//              state->buffer[state->buffer_used++] = buf[i];//接收什麼傳送什麼,不經過轉換,測試用
            if (buf[i] == '\n') //如果遇到換行,新增寫事件,並設定寫事件的大小
            {
                assert(state->write_event);
                event_add(state->write_event, NULL);
                state->write_upto = state->buffer_used;
                printf("遇到換行符,state->write_upto: %d, state->buffer_used: %d\n",state->write_upto, state->buffer_use
d);
            }
        }
        printf("recv once, state->buffer_used: %d\n", state->buffer_used);
}

    //判斷最後一次接收的位元組數
    if (result == 0)
    {
        free_fd_state(state);
    }
    else if (result < 0)
    {
        if (errno == EAGAIN) // XXXX use evutil macro
            return;
        perror("recv");
        free_fd_state(state);
    }
}

void do_write(evutil_socket_t fd, short events, void *arg)
{
    struct fd_state *state = arg;

    printf("\ncome in do_write, fd: %d, state->n_written: %d, state->write_upto: %d\n",fd, state->n_written, state->write
_upto);
    while (state->n_written < state->write_upto)
    {
        ssize_t result = send(fd, state->buffer + state->n_written, state->write_upto - state->n_written, 0);
        if (result < 0) {
            if (errno == EAGAIN) // XXX use evutil macro
                return;
            free_fd_state(state);
            return;
        }
        assert(result != 0);

        state->n_written += result;
        printf("send fd: %d, send size: %d, state->n_written: %d\n", fd, result, state->n_written);
    }

    if (state->n_written == state->buffer_used)
    {
        printf("state->n_written == state->buffer_used: %d\n", state->n_written);
        state->n_written = state->write_upto = state->buffer_used = 1;
        printf("state->n_written = state->write_upto = state->buffer_used = 1\n");
    }

    event_del(state->write_event);
}

void do_accept(evutil_socket_t listener, short event, void *arg)
{
    struct event_base *base = arg;
    struct sockaddr_storage ss;
    socklen_t slen = sizeof(ss);
    int fd = accept(listener, (struct sockaddr*)&ss, &slen);
    if (fd < 0)
    { // XXXX eagain??
        perror("accept");
    }
    else if (fd > FD_SETSIZE)
    {
        close(fd); // XXX replace all closes with EVUTIL_CLOSESOCKET */
    }
    else
    {
        struct fd_state *state;
        evutil_make_socket_nonblocking(fd);
        state = alloc_fd_state(base, fd);
        assert(state); /*XXX err*/
        assert(state->write_event);
        event_add(state->read_event, NULL);
    }
}

void run(void)
{
    evutil_socket_t listener;
    struct sockaddr_in sin;
    struct event_base *base;
    struct event *listener_event;

    base = event_base_new();//初始化libevent
    if (!base)
        return; /*XXXerr*/

    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = 0;//本機
    sin.sin_port = htons(8000);

    listener = socket(AF_INET, SOCK_STREAM, 0);
    evutil_make_socket_nonblocking(listener);

#ifndef WIN32
    {
        int one = 1;
        setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
    }
#endif

    if (bind(listener, (struct sockaddr*)&sin, sizeof(sin)) < 0)
    {
        perror("bind");
        return;
  }
  
  
      if (listen(listener, 16)<0)
      {
          perror("listen");
          return;
      }
  
      listener_event = event_new(base, listener, EV_READ|EV_PERSIST, do_accept, (void*)base);
      /*XXX check it */
      event_add(listener_event, NULL);
  
      event_base_dispatch(base);
  }
  
  int main(int c, char **v)
  {
  //    setvbuf(stdout, NULL, _IONBF, 0);
  
      run();
      return 0;
  }

編譯:gcc -I/usr/include -o test lowlevel_libevent_server.c -L/usr/local/lib -levent

執行結果:



相關推薦

處理併發 libevent demo詳細分析對比epoll

處理大併發之四 libevent demo詳細分析(對比epoll) libevent預設情況下是單執行緒,每個執行緒有且僅有一個event_base,對應一個struct event_base結構體,以及賦予其上的事件管理器,用來安排託管給它的一系列的事件。 當有一個事件

處理併發 libevent demo詳細分析對比epoll

libevent預設情況下是單執行緒,每個執行緒有且僅有一個event_base,對應一個struct event_base結構體,以及賦予其上的事件管理器,用來安排託管給它的一系列的事件。 當有一個事件發生的時候,event_base會在合適的時間去呼叫繫結在

程式設計菜鳥到路:C語言程式十二

第十二天學習精要 遞迴初步 遞迴 一個函式,自己呼叫自己,就是遞迴。 # include <iostream> using namespace std; int factorial(int n) // 函式返回n的階乘 { if (n ==

c/c++常用程式碼爆炸輸出,jason純乾貨

常用程式碼之四:建立jason,jason轉換為字串,字串轉換回jason,c#反序列化jason字串的幾個程式碼片段 建立j

LinkedHashMap 原始碼詳細分析JDK1.8

1. 概述 LinkedHashMap 繼承自 HashMap,在 HashMap 基礎上,通過維護一條雙向連結串列,解決了 HashMap 不能隨時保持遍歷順序和插入順序一致的問題。除此之外,LinkedHashMap 對訪問順序也提供了相關支援。在一些場景下,該特性很有用,比如快取。在實現上

hostapd wpa_supplicant madwifi詳細分析十二——EAPRFC3748及EAP狀態機分析RFC4137

這篇文章分兩個部分:EAP(RFC3748)及EAP狀態機分析(RFC4137),其中主要內容來自RFC以及網路文章。 一、EAP拓展認證協議 EAP的可拓展性主要表現在它的method可拓展,EAP只是一個載體,傳送不同method間的互動。 EAP可用於專用的連結,以

lk啟動流程詳細分析高通

int boot_linux_from_mmc(void)                                   { struct boot_img_hdr *hdr = (void*) buf;       //************buf和hdr指向相同的地址,可以理解為buf

C++11併發學習:執行緒同步

有時候,在第一個執行緒完成前,可能需要等待另一個執行緒執行完成。C++標準庫提供了一些工具可用於這種同步操作,形式上表現為條件變數(condition variable)和期望(future)。 一.條件變數(condition variable) C++標準庫對條件變數有兩套實現:std::c

java併發資料庫層面解決方案

    前言:當一個網站開始剛剛建立時,可能只是考慮一天只有幾十或者幾百個人訪問,資料庫可能就個db,所有表都放一起,一臺普通的伺服器可能就夠了,而且開發人員也非常高興,而且信心十足,因為所有的表都在一個庫中,這樣查詢語句就可以隨便關聯了,多美的一件事情。但是隨著訪問壓力的增加,

資料 hadoop HDFS HA 高可用的完全分散式

HDFS HA HA即為High Availability,用於解決NameNode單點故障問題,該特性通過熱備的方式為主NameNode提供一個備用者,一旦主NameNode出現故障,可以迅速切換至備NameNode,從而實現對外提供更穩定的服務 Second

小談php處理 併發 流量 儲存

一、判斷大型網站的標準: 1.pv(page views)網頁的瀏覽量: 概念:一個網站所有的頁面,在24小時內被訪問的總的次數。千萬級別,百萬級別, 2、uv值(unique vistor)獨立訪客 概念:一個網站,在24小時內,有多少個使用者來訪問我

Goroutine協程為何能處理併發

簡單來說:協程十分輕量,可以在一個程序中執行有數以十萬計的協程,依舊保持高效能。 程序、執行緒、協程的關係和區別: 程序擁有自己獨立的堆和棧,既不共享堆,亦不共享棧,程序由作業系統排程。 執行緒擁有自己獨立的棧和共享的堆,共享堆,不共享棧,執行緒亦由作業系統排程(標準執行緒是的)。 協程和執行緒一

處理併發之一 對epoll的理解,epoll客戶端服務端程式碼

處理大併發之一 對epoll的理解,epoll客戶端服務端程式碼 序言: 該部落格是一系列的部落格,首先從最基礎的epoll說起,然後研究libevent原始碼及使用方法,最後研究nginx和node.js,關於select,poll這裡不做說明,只說明其相對於epoll的

python 處理資料資料讀取

1 參考1:python讀取GB級的文字資料,防止memoryError Preliminary   我們談到“文字處理”時,我們通常是指處理的內容。Python 將文字檔案的內容讀入可以操作的字串變數非常容易。檔案物件提供了三個“讀”方法: .read()、.read

Flink處理函式實戰:視窗處理

### 歡迎訪問我的GitHub [https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) 內容:所有原創文章分類彙總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等; ### F

MySqlALTER命令用法詳細解讀

修改表 pre const 命令使用 add ear 修改 blog rain 本文詳細解讀了MySql語法中Alter命令的用法,這是一個用法比較多的語法,而且功能還是很強大的。 USE learning;(自己要提前建好) CREATE TABLE student

Flutterdrawer詳細分析你要的操作都有

1. 簡介 這篇文章主要講解有關drawer的一切。 另:接Flutter相關專案,需要的私信或通過QQ:708959817,聯絡我 2. 初探 我們先來看看簡單的drawer在Flutter的應用 class HomePage extends StatefulWidget {

1.資料指CDH叢集搭建詳細步驟

1.使用CDH,其中CDH表示的意思是Cloudera’s Distribution Including Apache Hadoop,簡稱“CDH”) 基於web的使用者介面,支援大多數的hadoop元件,包括了HDFS,MapReduce以及HIve和Pig Hbase以及Zookeepe

ccf歷年第題java解答-201503-4-網路延時90分

使用bfs求樹的直徑,執行超時,90分 import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; class Node{ public int no; public int

ccf歷年第題java解答-201412-4-最優灌溉100分

使用kruskal求解,耗時943ms,得分100 徘徊在超時的邊緣,同樣的程式碼,有時候提交是100分,有時候是超時90分,還有時候是超時80分== import java.util.ArrayList; import java.util.Collections; import jav