Skip to content
forked from idealvin/coost

A go-style coroutine library in C++11 and more.

License

Notifications You must be signed in to change notification settings

wangscript007/co

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

A go-style C++ coroutine library and more.

co is an elegant and efficient C++ base library that supports Linux, Windows and Mac platforms. It contains a golang-style coroutine library, network library, log library, command line and configuration file parsing library, unit test framework, JSON library and other basic components.

co follows a minimalist design concept, and the interfaces provided are as simple and clear as possible, and users can easily get started. co tries to avoid excessive encapsulation which may introduce too many concepts, to reduce the learning burden of users. For example, the coroutineized socket API provided by co is nearly the same in form as the native socket API. Users who are familiar with socket programming nearly need no more cost of learning, and can easily use these APIs to write high-performance network programs.

Documents

Highlights

Coroutine (co)

co is a go-style C++ coroutine library with the following features:

  • Multi-thread scheduling, the default number of threads is the number of system CPU cores.

  • Coroutines share the thread stack (default size is 1MB), and the memory footprint is low, a single machine can easily create millions of coroutines.

  • System api hook. It is easy to use third-party network libraries in coroutines.

  • Coroutine lock co::Mutex.

  • Coroutine synchronization event co::Event.

  • Coroutine Pool co::Pool.

  • Coroutineized socket API.

  • create coroutine with go():

    void ku() {
        LOG << "hello world";
    }
    
    void gg(int v) {
        LOG << "hello "<< v;
    }
    
    go(ku);  // Goku
    go(gg, 777);
    go([](){
        LOG << "hello go";
    });

Network (so)

so is a C++ network library based on coroutines. It provides a general ipv6-compatible TCP framework and implements a simple json-based rpc framework, and also provides an optional support for HTTP, HTTPS and SSL.

  • Simple static web server

    #include "co/flag.h"
    #include "co/log.h"
    #include "co/so.h"
    
    DEF_string(d, ".", "root dir"); // Specify the root directory of the web server
    
    int main(int argc, char** argv) {
        flag::init(argc, argv);
        log::init();
    
        so::easy(FLG_d.c_str()); // mum never have to worry again
    
        return 0;
    }
  • http server (openssl required for https)

    http::Server serv;
    
    serv.on_req(
        [](const http::Req& req, http::Res& res) {
            if (req.is_method_get()) {
                if (req.url() == "/hello") {
                    res.set_status(200);
                    res.set_body("hello world");
                } else {
                    res.set_status(404);
                }
            } else {
                res.set_status(405); // method not allowed
            }
        }
    );
    
    serv.start("0.0.0.0", 80);                                    // http
    serv.start("0.0.0.0", 443, "privkey.pem", "certificate.pem"); // https
  • http client (libcurl & zlib required)

    http::Client c("http://127.0.0.1:7777"); // http
    http::Client c("https://github.com");    // https, openssl required
    c.add_header("hello", "world");          // add headers here
    
    c.get("/");
    LOG << "response code: "<< c.response_code();
    LOG << "body size: "<< c.body_size();
    LOG << "Content-Length: "<< c.header("Content-Length");
    LOG << c.header();
    
    c.post("/hello", "data xxx");
    LOG << "response code: "<< c.response_code();

Some features from golang

defer

#include "co/defer.h"
#include <iostream>

void f(int x, int y) { std::cout << (x + y) << std::endl; }

int main(int argc, char** argv) {
    int x = 1, y = 2;
    defer(f(3, 4); f(4, 3));
    defer(f(x, y));
    return 0;
}

waitgroup

#include "co/co.h"

co::WaitGroup wg;

for (int i = 0; i < 8; ++i) {
    wg.add();
    go([&]() {
        // do ...
        wg.done();
    });
}

wg.wait();

Log library (log)

log is a high-performance local log system.

  • Print logs

    LOG << "hello " << 23; // info
    DLOG << "hello" << 23; // debug
    WLOG << "hello" << 23; // warning
    ELOG << "hello again"; // error
  • Performance vs glog

    log vs glog google glog co/log
    win2012 HHD 1.6MB/s 180MB/s
    win10 SSD 3.7MB/s 560MB/s
    mac SSD 17MB/s 450MB/s
    linux SSD 54MB/s 1023MB/s

The above table is the test result of one million info logs (about 50 bytes each) continuously printed by a single thread. The co/log is almost two orders of magnitude faster than glog.

Why is it so fast? The first is that it is based on fastream that is 8-25 times faster than sprintf. The second is that it has almost no memory allocation operations.

Command line and configuration file parsing (flag)

flag is a convenient and easy-to-use command line and configuration file parsing library that supports automatic generation of configuration files.

  • Code example

    #include "co/flag.h"
    
    DEF_int32(i, 32, "comments");
    DEF_string(s, "xxx", "string type");
    
    int main(int argc, char** argv) {
        flag::init(argc, argv);
        std::cout << "i: "<< FLG_i << std::endl;
        std::cout << "s: "<< FLG_s << std::endl;
        return 0;
    }
  • Build and run

    ./xx                         # start with default config values
    ./xx -i=4k -s="hello world"  # integer types can take units k,m,g,t,p, non-case sensitive
    ./xx -i 4k -s "hello world"  # same as above
    ./xx --mkconf                # generate configuration file xx.conf
    ./xx xx.conf                 # start from configuration file
    ./xx -config xx.conf         # start from configuration file

JSON

JSON is an easy-to-use, high-performance JSON library. The latest version stores the JSON object in a piece of contiguous memory, nearly no memory allocation is needed during pasing Json from a string, which greatly improves the parsing speed(GB per second).

  • Code example
    #include "co/json.h"
    
    // Json: {"hello":"json", "array":[123, 3.14, true, "nice"]}
    json::Root r;
    r.add_member("hello", "json");        // add key:value pair
    
    json::Value a = r.add_array("array"); // add key:array
    a.push_back(123, 3.14, true, "nice"); // push value to array, accepts any number of parameters
    
    COUT << a[0].get_int();               // 123
    COUT << r["array"][0].get_int();      // 123
    COUT << r["hello"].get_string();      // "json"
    
    fastring s = r.str();                 // convert Json to string
    fastring p = r.pretty();              // convert Json to human-readable string
    json::Root x = json::parse(s);        // parse Json from a string

Code composition

  • co/include

    Header files of libco.

  • co/src

    Source files of libco.

  • co/test

    Some test codes, each .cc file will be compiled into a separate test program.

  • co/unitest

    Some unit test codes, each .cc file corresponds to a different test unit, and all codes will be compiled into a single test program.

  • co/gen

    A code generation tool automatically generates rpc framework code according to the proto file.

Building

Compilers required

xmake

co recommends using xmake as the build tool.

  • Install xmake

    For windows, mac and debian/ubuntu, you can go directly to the release page of xmake to get the installation package. For other systems, please refer to xmake's Installation instructions.

    Xmake disables compiling as root by default on linux. ruki says it is not safe. You can add the following line to ~/.bashrc to enable it:

    export XMAKE_ROOT=y
  • Quick start

    # All commands are executed in the root directory of co (the same below)
    xmake      # build libco by default
    xmake -a   # build all projects (libco, gen, co/test, co/unitest)
  • build with libcurl, openssl (enable HTTP/SSL features)

    xmake f --with_libcurl=true --with_openssl=true
    xmake
  • build libco

    xmake build libco     # build libco only
    xmake -b libco        # same as above
    xmake -v -b libco     # same as above, but print more compiling info
    xmake -vD -b libco    # same as above, but print more compiling info
  • build and run unitest code

    co/unitest contains some unit test codes, which are used to check the correctness of the functionality of libco.

    xmake build unitest    # build can be abbreviated as -b
    xmake run unitest -a   # run all unit tests
    xmake r unitest -a     # same as above
    xmake r unitest -os    # run unit test os
    xmake r unitest -json  # run unit test json
  • build and run test code

    co/test contains some test codes. You can easily add a source file like xxx.cc in the directory co/test or its subdirectories, and then run xmake build xxx to build it.

    xmake build flag             # test/flag.cc
    xmake build log              # test/log.cc
    
    xmake r flag -xz             # test flag
    xmake r log                  # test log
    xmake r log -cout            # also log to terminal
    xmake r log -perf            # performance test
  • build gen

    # It is recommended to put gen in the system directory (e.g. /usr/local/bin/).
    xmake build gen
    cp gen /usr/local/bin/
    gen hello_world.proto

    Proto file format can refer to hello_world.proto.

  • Install libco

    # Install header files and libco by default.
    xmake install -o pkg         # package related files to the pkg directory
    xmake i -o pkg               # the same as above
    xmake install -o /usr/local  # install to the /usr/local directory
  • Install libco from xmake repo

    xrepo install -f "with_openssl=true,with_libcurl=true" co

cmake

izhengfan helped provide cmake support:

  • By default, only build libco.

  • The library files are in the build/lib directory, and the executable files are in the build/bin directory.

  • You can use BUILD_ALL to compile all projects.

  • You can use CMAKE_INSTALL_PREFIX to specify the installation directory.

  • cmake only provides simple options, if you need more complex configuration, please use xmake.

  • Build libco by default

    mkdir build && cd build
    cmake ..
    make -j8
  • Build all projects

    mkdir build && cd build
    cmake .. -DBUILD_ALL=ON -DCMAKE_INSTALL_PREFIX=pkg
    make -j8
    make install
  • Build with libcurl & openssl (libcurl, zlib, openssl 1.1.0 or above required)

    mkdir build && cd build
    cmake .. -DBUILD_ALL=ON -DWITH_LIBCURL=ON
    make -j8

Build from Docker

docker build -t co:v2.0.0 .
docker run -itd -v $(pwd):/home/co/ co:v2.0.0
docker exec -it ${CONTAINER_ID} bash    #replace with true CONTAINER_ID

# execute the following command in docker
cd /home/co && mkdir build && cd build
cmake .. -DBUILD_ALL=ON -DWITH_LIBCURL=ON
make -j8

License

The MIT license. co contains codes from some other projects, which have their own licenses, see details in LICENSE.md.

Special thanks

  • The code of co/context is from tbox by ruki, special thanks!
  • The English reference documents of co are translated by Leedehai (1-10), daidai21 (11-15) and google, special thanks!
  • ruki has helped to improve the xmake building scripts, thanks in particular!
  • izhengfan provided cmake building scripts, thank you very much!

Donate

Goto the Donate page.

About

A go-style coroutine library in C++11 and more.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C++ 92.9%
  • Assembly 5.2%
  • C 0.8%
  • CMake 0.4%
  • Lua 0.3%
  • Makefile 0.3%
  • Other 0.1%