1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/acl-dev-acl

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
README_en.md 14 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 01.12.2024 23:24 e23031c

Высокопроизводительная библиотека корутин, поддерживающая Linux/BSD/Mac/Windows

中文说明

О проекте

Проект libfiber берёт начало от модуля корутины проекта acl и находится в каталоге lib_fiber. Его можно использовать на платформах ОС, включая Linux, FreeBSD, MacOS и Windows, которые поддерживают select, poll, epoll, io-uring, kqueue, iocp и даже сообщения Windows GUI для разных платформ. С помощью libfiber вы можете писать сетевые приложения с высокой производительностью и большим количеством одновременных подключений легче, чем в традиционных асинхронных фреймворках с управляемой событиями моделью. Более того, с помощью libfiber можно даже писать сетевой модуль для приложений Windows GUI, написанных на MFC, wtl или других фреймворках, в стиле корутин. Это действительно потрясающе.

Какие события ввода-вывода поддерживаются ?

Libfiber поддерживает множество событий, включая select/poll/epoll/io-uring/kqueue и сообщения Windows GUI.

Платформа Тип события
Linux select, poll, epoll, io-uring
BSD select, poll, kqueue
Mac select, poll, kqueue
Windows select, poll, iocp, сообщения GUI

Примеры

Пример сервера с одним клиентом

// fiber_server.c

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "fiber/lib_fiber.h"
#include "patch.h" // in the samples path

static size_t      __stack_size  = 128000;
static const char *__listen_ip   = "127.0.0.1";
static int         __listen_port = 9001;

static void fiber_client(ACL_FIBER *fb, void *ctx)
{
    SOCKET *pfd = (SOCKET *) ctx;
    char buf[8192];

    while (1) {
#if defined(_WIN32)
        int ret = acl_fiber_recv(*pfd, buf, sizeof(buf), 0);
#else
        int ret = recv(*pfd, buf, sizeof(buf), 0);
#endif
        if (ret == 0) {
            break;
        } else if (ret < 0) {
            if (acl_fiber_last_error() == FIBER_EINTR) {
                continue;
            }
            break;
        }
#if defined(_WIN32)
        if (acl_fiber_send(*pfd, buf, ret, 0) < 0) {
#else
        if (send(*pfd, buf, ret, 0) < 0) {
#endif          
            break;
        }
    }

    socket_close(*pfd);
    free(pfd);
}

static void fiber_accept(ACL_FIBER *fb, void *ctx)
{
    const char *addr = (const char *) ctx;
    SOCKET lfd = socket_listen(__listen_ip, __listen_port);

    assert(lfd >= 0);

    for (;;) {
        SOCKET *pfd, cfd = socket_accept(lfd);
        if (cfd == INVALID_SOCKET) {
            printf("accept error %s\r\n", acl_fiber_last_serror());
            break;
        }
        pfd = (SOCKET *) malloc(sizeof(SOCKET));
        *pfd = cfd;

        // create and start one fiber to handle the client socket IO
        acl_fiber_create(fiber_client, pfd, __stack_size);
    }

    socket_close(lfd);
    exit (0);
}

// FIBER_EVENT_KERNEL представляет тип события на
// Linux(epoll), BSD(kqueue), Mac(kqueue), Windows(iocp)
// FIBER_EVENT_POLL: poll на Linux/BSD/Mac/Windows
// FIBER_EVENT_SELECT: select на Linux/BSD/Mac/Windows
// FIBER_EVENT_WMSG: Win GUI message на Windows
// acl_fiber_create/acl_fiber_schedule_with находятся в `lib_fiber.h`.
// socket_listen/socket_accept/socket_close находятся в patch.c из пути примеров.

int main(void)
{
    int event_mode = FIBER_EVENT_KERNEL;

#if defined(_WIN32)
    socket_init();
#endif

    // create
...

**Примечание:** В запросе присутствуют фрагменты кода на языке C. В ответе они сохранены без изменений. **Один из вариантов перевода текста на русский язык:**

### Один клиентский образец
```C
// fiber_client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "fiber/lib_fiber.h"
#include "patch.h" // в папке с образцами

static const char *__server_ip   = "127.0.0.1";
static int         __server_port = 9001;

// socket_init/socket_end/socket_connect/socket_close находятся в patch.c папки с образцами

static void fiber_client(ACL_FIBER *fb, void *ctx)
{
    SOCKET cfd = socket_connect(__server_ip, __server_port);
    const char *s = "hello world\r\n";
    char buf[8192];
    int i, ret;

    if (cfd == INVALID_SOCKET) {
        return;
    }

    for (i = 0; i < 1024; i++) {
#if defined(_WIN32)
        if (acl_fiber_send(cfd, s, strlen(s), 0) <= 0) {
#else
        if (send(cfd, s, strlen(s), 0) <= 0) {
#endif          
            printf("send error %s\r\n", acl_fiber_last_serror());
            break;
        }

#if defined(_WIN32)
        ret = acl_fiber_recv(cfd, buf, sizeof(buf), 0);
#else
        ret = recv(cfd, buf, sizeof(buf), 0);
#endif      
        if (ret <= 0) {
            break;
        }
    }

#if defined(_WIN32)
    acl_fiber_close(cfd);
#else
    close(cfd);
#endif
}

int main(void)
{
    int event_mode = FIBER_EVENT_KERNEL;
    size_t stack_size = 128000;

    int i;

#if defined(_WIN32)
    socket_init();
#endif

    for (i = 0; i < 100; i++) {
        acl_fiber_create(fiber_client, NULL, stack_size);
    }

    acl_fiber_schedule_with(event_mode);

#if defined(_WIN32)
    socket_end();
#endif

    return 0;
}

Сервер сопрограмм с C++

#include "acl_cpp/lib_acl.hpp"
#include "fiber/libfiber.hpp"

class fiber_client : public acl::fiber {
public:
    fiber_client(acl::socket_stream* conn) : conn_(conn) {}

private:
    ~fiber_client(void) { delete conn_; }

private:
    acl::socket_stream* conn_;

    // @override
    void run(void) {
        char buf[256];
        while (true) {
            int ret = conn_->read(buf, sizeof(buf), false);
            if (ret <= 0) {
                break;
            }
            if (conn_->write(buf, ret) != ret) {
                break;
            }
        }

        delete this;
    }
};

class fiber_server : public acl::fiber {
public:
    fiber_server(acl::server_socket& server) : server_(server) {}

private:
    ~fiber_server(void) {}

private:
    acl::server_socket& server_;

    // @override
    void run(void) {
        while (true) {
            acl::socket_stream* conn = server_.accept();
            if (conn) {
                acl::fiber* fb = new fiber_client(conn);
                fb->start();
            }
        }

        delete this;
    }
};

int main(void) {
    const char* addr = "127.0.0.1:8088";
    acl::server_socket server;
    if (!server.open(addr)) {
        return 1;
    }

    // Создаём одну серверную сопрограмму для ожидания соединения.
    acl::fiber* fb = new fiber_server(server);
    fb->start();

    acl::fiber::schedule();  // Запускаем процесс расписания сопрограммы.
    return 0;
}

Сервер сопрограмм с С++11

#include "acl_cpp/lib_acl.hpp"
#include "fiber/go_fiber.hpp"

int main(void) {
    const char* addr = "127.0.0.1:8088";
    acl::server_socket server;
    if (!server.open(addr)) {
        return 1;
    }

    // Создаём одну серверную сопрограмму для ожидания соединения.
    go[=, &server] {
        while (true) {
            acl::socket_stream* conn = server.accept();
            if (conn) {
                // Создаём одну клиентскую сопрограмму для обработки соединения.
                go[conn] {
                    char buf[256];
                    while (true) {
                        int ret = conn->read(buf, sizeof(buf), false);
                        if (ret <= 0) {
                            break;
                        }
                        if (conn->write(buf, ret) != ret) {

``` **ACL_FIBER_RWLOCK**  
- acl_fiber_rwlock_tryrlock  
- acl_fiber_rwlock_wlock  
- acl_fiber_rwlock_trywlock  
- acl_fiber_rwlock_runlock  
- acl_fiber_rwlock_wunlock  

**ACL_FIBER_EVENT**  
- acl_fiber_event_create  
- acl_fiber_event_free  
- acl_fiber_event_wait  
- acl_fiber_event_trywait  
- acl_fiber_event_notify  

**ACL_FIBER_SEM**  
- acl_fiber_sem_create  
- acl_fiber_sem_free  
- acl_fiber_sem_wait  
- acl_fiber_sem_post  
- acl_fiber_sem_num  

## About API Hook
В Linux/BSD/Mac перехватываются многие IO и сетевые API. Поэтому вы можете просто использовать стандартные системные API в своих приложениях с libfiber, перехватченные API будут заменены на API libfiber. В этом случае вы можете *сопрограммировать* ваше приложение БД с управлением MySQL и ничего не менять в управлении MySQL.  
Ниже приведены стандартные API, которые были перехвачены:  
 close;  
 sleep;  
 read;  
 readv;  
 recv;  
 recvfrom;  
 recvmsg;  
 write;  
 writev;  
 send;  
 sendto;  
 sendmsg;  
 sendfile64;  
 socket;  
 listen;  
 accept;  
 connect;  
 select;  
 poll;  
 epoll: epoll_create, epoll_ctl, epoll_wait;  
 gethostbyname(_r);  
 getaddrinfo/freeaddrinfo.

## FAQ
1. **Планируется ли расписание сопрограмм в многопоточном режиме?**  
Нет. Расписание сопрограммы libfiber осуществляется в одном потоке. Но вы можете запустить несколько потоков, каждый из которых имеет свой процесс расписания.  
2. **Как используются многоядерные процессоры?**  
Можно запускать несколько потоков со своим расписанием сопрограмм, каждый поток может занимать одно ядро процессора.  
3. **Каким образом разные потоки используют мьютексы в состоянии расписания сопрограмм?**  
Хотя можно использовать системные мьютекс-API, такие как pthread_mutex_t, рекомендуется использовать ACL_FIBER_EVENT API. Это безопасно, когда системные мьютекс-API используются в течение короткого времени без рекурсивного вызова. Однако небезопасно использовать системные мьютекс-API в этом случае: одна сопрограмма A1 потока A заблокировала поток-мьютекс-A, сопрограмма A2 потока A хотела заблокировать поток-мьютекс-B, который был заблокирован одной сопрограммой B1 потока B, когда сопрограмма B2 потока B хотела заблокировать поток-мьютекс-A, произошла тупиковая ситуация! Таким образом, были созданы мьютексы сопрограмм для потоков и сопрограмм с именем ACL_FIBER_EVENT, которые можно использовать для создания критической области между несколькими сопрограммами в разных потоках (несколько продолжений в одном и том же потоке или нет; его также можно использовать для разных потоков без сопрограмм).  
4. **Нужно ли изменять исходный код, управляемый MySQL, при использовании с libfiber?**  
В UNIX OS системные IO API перехватываются libfiber, поэтому в MySQL-управляемом ничего менять не нужно.  
5. **Как избежать перегрузки mysqld при запуске множества сопрограмм?**  
Для защиты mysqld от перегрузки множеством соединений множества сопрограмм можно использовать API ACL_FIBER_SEM. Эти API могут ограничить количество подключений к mysqld из сопрограмм.  
6. **Блокирует ли разрешение доменного имени DNS расписание сопрограмм?**  
Нет, потому что системные API разрешения доменных имён, такие как gethostbyname(_r) и getaddrinfo, также перехватываются в libfiber.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/acl-dev-acl.git
git@api.gitlife.ru:oschina-mirror/acl-dev-acl.git
oschina-mirror
acl-dev-acl
acl-dev-acl
master