Giter VIP home page Giter VIP logo

coost's Introduction

Coost

English | 简体中文

Linux Build Windows Build Mac Build Release License: MIT

A tiny boost library in C++11.

0. Introduction

coost is an elegant and efficient cross-platform C++ base library. Its goal is to create a sword of C++ to make C++ programming easy and enjoyable.

Coost, co for short, is like boost, but more lightweight, the static library built on linux or mac is only about 1MB in size. However, it still provides enough powerful features:

  • Command line and config file parser (flag)
  • High performance log library (log)
  • Unit testing framework
  • Bechmark testing framework
  • go-style coroutine
  • Coroutine-based network library
  • JSON RPC framework
  • Atomic operation (atomic)
  • Efficient stream (fastream)
  • Efficient string (fastring)
  • String utility (str)
  • Time library (time)
  • Thread library (thread)
  • Timed Task Scheduler
  • God-oriented programming
  • Efficient JSON library
  • Hash library
  • Path library
  • File utilities (fs)
  • System operations (os)
  • Fast memory allocator

1. Sponsor

Coost needs your help. If you are using it or like it, you may consider becoming a sponsor. Thank you very much!

2. Documents

3. Core features

3.0 God-oriented programming

co/god.h provides some features based on templates.

#include "co/god.h"

void f() {
    god::bless_no_bugs();
    god::is_same<T, int, bool>(); // T is int or bool?
}

3.1 flag

flag is a command line and config file parser. It is similar to gflags, but more powerful:

  • Support parameters from both command-line and config file.
  • Support automatic generation of the config file.
  • Support flag aliases.
  • Flag of integer type, the value can take a unit k,m,g,t,p.
#include "co/flag.h"
#include "co/cout.h"

DEF_bool(x, false, "x");
DEF_bool(y, true, "y");
DEF_bool(debug, false, "dbg", d);
DEF_uint32(u, 0, "xxx");
DEF_string(s, "", "xx");

int main(int argc, char** argv) {
    flag::parse(argc, argv);
    cout << "x: " << FLG_x << '\n';
    cout << "y: " << FLG_y << '\n';
    cout << "debug: " << FLG_debug << '\n';
    cout << "u: " << FLG_u << '\n';
    cout << FLG_s << "|" << FLG_s.size() << '\n';
    return 0;
}

In the above example, the macros start with DEF_ define 4 flags. Each flag corresponds to a global variable, whose name is FLG_ plus the flag name. The flag debug has an alias d. After building, the above code can run as follow:

./xx                  # Run with default configs
./xx -x -s good       # x -> true, s -> "good"
./xx -debug           # debug -> true
./xx -xd              # x -> true, debug -> true
./xx -u 8k            # u -> 8192

./xx -mkconf          # Automatically generate a config file: xx.conf
./xx xx.conf          # run with a config file
./xx -conf xx.conf    # Same as above

3.2 log

log is a high-performance log library, some components in coost use it to print logs.

log supports two types of logs: one is level log, which is divided into 5 levels: debug, info, warning, error and fatal, printing a fatal log will terminate the program; the other is topic log, logs are grouped by topic, and logs of different topics are written to different files.

#include "co/log.h"

int main(int argc, char** argv) {
    flag::parse(argc, argv);

    TLOG("xx") << "s" << 23; // topic log
    DLOG << "hello " << 23;  // debug
    LOG << "hello " << 23;   // info
    WLOG << "hello " << 23;  // warning
    ELOG << "hello " << 23;  // error
    FLOG << "hello " << 23;  // fatal

    return 0;
}

co/log also provides a series of CHECK macros, which is an enhanced version of assert, and they will not be cleared in debug mode.

void* p = malloc(32);
CHECK(p != NULL) << "malloc failed..";
CHECK_NE(p, NULL) << "malloc failed..";

log is very fast, the following are some test results:

platform glog co/log speedup
win2012 HHD 1.6MB/s 180MB/s 112.5
win10 SSD 3.7MB/s 560MB/s 151.3
mac SSD 17MB/s 450MB/s 26.4
linux SSD 54MB/s 1023MB/s 18.9

The above is the write speed of co/log and glog (single thread, 1 million logs). It can be seen that co/log is nearly two orders of magnitude faster than glog.

threads linux co/log linux spdlog win co/log win spdlog speedup
1 0.087235 2.076172 0.117704 0.461156 23.8/3.9
2 0.183160 3.729386 0.158122 0.511769 20.3/3.2
4 0.206712 4.764238 0.316607 0.743227 23.0/2.3
8 0.302088 3.963644 0.406025 1.417387 13.1/3.5

The above is the time of printing 1 million logs with 1, 2, 4, and 8 threads, in seconds. Speedup is the performance improvement of co/log compared to spdlog on linux and windows platforms.

3.3 unitest

unitest is a simple and easy-to-use unit test framework. Many components in coost use it to write unit test code, which guarantees the stability of coost.

#include "co/unitest.h"
#include "co/os.h"

DEF_test(os) {
    DEF_case(homedir) {
        EXPECT_NE(os::homedir(), "");
    }

    DEF_case(cpunum) {
        EXPECT_GT(os::cpunum(), 0);
    }
}
 
int main(int argc, char** argv) {
    flag::parse(argc, argv);
    unitest::run_tests();
    return 0;
}

The above is a simple example. The DEF_test macro defines a test unit, which is actually a function (a method in a class). The DEF_case macro defines test cases, and each test case is actually a code block.

The directory unitest contains the unit test code in coost. Users can run unitest with the following commands:

xmake r unitest      # Run all test cases
xmake r unitest -os  # Run test cases in the os unit

3.4 JSON

In coost v3.0, Json provides fluent APIs, which is more convenient to use.

// {"a":23,"b":false,"s":"123","v":[1,2,3],"o":{"xx":0}}
co::Json x = {
    { "a", 23 },
    { "b", false },
    { "s", "123" },
    { "v", {1,2,3} },
    { "o", {
        {"xx", 0}
    }},
};

// equal to x
co::Json y = Json()
    .add_member("a", 23)
    .add_member("b", false)
    .add_member("s", "123")
    .add_member("v", Json().push_back(1).push_back(2).push_back(3))
    .add_member("o", Json().add_member("xx", 0));

x.get("a").as_int();       // 23
x.get("s").as_string();    // "123"
x.get("s").as_int();       // 123, string -> int
x.get("v", 0).as_int();    // 1
x.get("v", 2).as_int();    // 3
x.get("o", "xx").as_int(); // 0

x["a"] == 23;          // true
x["s"] == "123";       // true
x.get("o", "xx") != 0; // false
os co/json stringify co/json parse rapidjson stringify rapidjson parse speedup
win 569 924 2089 2495 3.6/2.7
mac 783 1097 1289 1658 1.6/1.5
linux 468 764 1359 1070 2.9/1.4

The above is the average time of stringifying and parsing minimized twitter.json, in microseconds (us), speedup is the performance improvement of co/json compared to rapidjson.

3.5 Coroutine

coost has implemented a go-style coroutine, which has the following features:

  • Support multi-thread scheduling, the default number of threads is the number of system CPU cores.
  • Shared stack, coroutines in the same thread share several stacks (the default size is 1MB), and the memory usage is low.
  • There is a flat relationship between coroutines, and new coroutines can be created from anywhere (including in coroutines).
  • Support coroutine synchronization events, coroutine locks, channels, and waitgroups.
#include "co/co.h"

int main(int argc, char** argv) {
    flag::parse(argc, argv);

    co::wait_group wg;
    wg.add(2);

    go([wg](){
        LOG << "hello world";
        wg.done();
    });

    go([wg](){
        LOG << "hello again";
        wg.done();
    });

    wg.wait();
    return 0;
}

In the above code, the coroutines created by go() will be distributed to different scheduling threads. Users can also control the scheduling of coroutines by themselves:

// run f1 and f2 in the same scheduler
auto s = co::next_sched();
s->go(f1);
s->go(f2);

// run f in all schedulers
for (auto& s : co::scheds()) {
    s->go(f);
}

3.6 network programming

coost provides a coroutine-based network programming framework:

  • coroutineized socket API, similar in form to the system socket API, users familiar with socket programming can easily write high-performance network programs in a synchronous manner.
  • TCP, HTTP, RPC and other high-level network programming components, compatible with IPv6, also support SSL, it is more convenient to use than socket API.

RPC server

#include "co/co.h"
#include "co/rpc.h"
#include "co/time.h"

int main(int argc, char** argv) {
    flag::parse(argc, argv);

    rpc::Server()
        .add_service(new xx::HelloWorldImpl)
        .start("127.0.0.1", 7788, "/xx");

    for (;;) sleep::sec(80000);
    return 0;
}

rpc::Server also supports HTTP protocol, you may use the POST method to call the RPC service:

curl http://127.0.0.1:7788/xx --request POST --data '{"api":"ping"}'

Static web server

#include "co/flag.h"
#include "co/http.h"

DEF_string(d, ".", "root dir"); // docroot for the web server

int main(int argc, char** argv) {
    flag::parse(argc, argv);
    so::easy(FLG_d.c_str()); // mum never have to worry again
    return 0;
}

HTTP server

void cb(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
    }
}

// http
http::Server().on_req(cb).start("0.0.0.0", 80);

// https
http::Server().on_req(cb).start(
    "0.0.0.0", 443, "privkey.pem", "certificate.pem"
);

HTTP client

void f() {
    http::Client c("https://github.com");

    c.get("/");
    LOG << "response code: "<< c.status();
    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.status();
}

go(f);

4. Code composition

  • include

    Header files of coost.

  • src

    Source files of coost, built as libco.

  • test

    Test code, each .cc file will be compiled into a separate test program.

  • unitest

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

  • gen

    A code generator for the RPC framework.

5. Building

5.1 Compilers required

To build coost, you need a compiler that supports C++11:

5.2 Build with xmake

coost recommends using xmake as the build tool.

5.2.1 Quick start

# All commands are executed in the root directory of coost (the same below)
xmake      # build libco by default
xmake -a   # build all projects (libco, gen, test, unitest)

5.2.2 Build shared library

xmake f -k shared
xmake -v

5.2.3 Build with mingw

xmake f -p mingw
xmake -v

5.2.4 Enable HTTP/SSL features

xmake f --with_libcurl=true --with_openssl=true
xmake -v

5.2.5 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

5.2.6 Install libco from xrepo

xrepo install -f "openssl=true,libcurl=true" coost

5.3 Build with cmake

izhengfan helped to provide cmake support, SpaceIm improved it and made it perfect.

5.3.1 Build libco

mkdir build && cd build
cmake ..
make -j8

5.3.2 Build all projects

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

5.3.3 Enable HTTP/SSL features

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

5.3.4 Build shared library

cmake .. -DBUILD_SHARED_LIBS=ON
make -j8

5.3.5 Find coost in Cmake

find_package(coost REQUIRED CONFIG)
target_link_libraries(userTarget coost::co)

5.3.6 vcpkg & conan

vcpkg install coost:x64-windows

# HTTP & SSL support
vcpkg install coost[libcurl,openssl]:x64-windows

conan install coost

6. License

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

7. Special thanks

  • The code of co/context is from tbox by ruki, special thanks!
  • The early English documents of co are translated by Leedehai and daidai21, special thanks!
  • ruki has helped to improve the xmake building scripts, thanks in particular!
  • izhengfan provided cmake building scripts, thank you very much!
  • SpaceIm has improved the cmake building scripts, and provided support for find_package. Really great help, thank you!

coost's People

Contributors

byronhe avatar codehz avatar daidai21 avatar frankhb avatar frederick-vs-ja avatar halft0n avatar hc-tec avatar ichn-hu avatar idealvin avatar izhengfan avatar kuyoonjo avatar leedehai avatar ltmit avatar qixuxiang avatar shihzh avatar shuai132 avatar sn0wywh1te avatar spaceim avatar tigerlee avatar ugotang avatar waruqi avatar zeno-sole avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

coost's Issues

cannot build with msvc x86

Under co/base/:

$ xmake f -a x86
checking for the Microsoft Visual Studio (x86) version ... 2019

$ xmake
[ 23%]: compiling.release co\impl\epoll.cc
[ 26%]: compiling.release co\impl\co_win.cpp
[ 29%]: compiling.release stack_trace\stack_trace_win.cpp
[ 33%]: compiling.release win\time.cpp
[ 39%]: compiling.release fast.cc
[  6%]: compiling.release fastring.cc
[  9%]: compiling.release hash\base64.cc
[ 16%]: compiling.release co\impl\co_unix.cc
[ 19%]: compiling.release json.cc
[ 42%]: compiling.release co\impl\scheduler.cc
[ 46%]: compiling.release unix\time.cc
[ 49%]: compiling.release win\os.cpp
[ 52%]: compiling.release str.cc
error: time.cpp
C:\Users\fzheng\source\repos\co\base\win/atomic.h(46): error C3861: '_InterlockedIncrement64': identifier not found
C:\Users\fzheng\source\repos\co\base\win/atomic.h(62): error C3861: '_InterlockedDecrement64': identifier not found
C:\Users\fzheng\source\repos\co\base\win/atomic.h(78): error C3861: '_InterlockedExchangeAdd64': identifier not found
C:\Users\fzheng\source\repos\co\base\win/atomic.h(94): error C3861: '_InterlockedExchangeAdd64': identifier not found
C:\Users\fzheng\source\repos\co\base\win/atomic.h(110): error C3861: '_InterlockedExchangeAdd64': identifier not found
C:\Users\fzheng\source\repos\co\base\win/atomic.h(126): error C3861: '_InterlockedExchangeAdd64': identifier not found
C:\Users\fzheng\source\repos\co\base\win/atomic.h(142): error C3861: '_InterlockedExchangeAdd64': identifier not found
C:\Users\fzheng\source\repos\co\base\win/atomic.h(158): error C3861: '_InterlockedExchangeAdd64': identifier not found
C:\Users\fzheng\source\repos\co\base\win/atomic.h(174): error C3861: '_InterlockedOr64': identifier not found
C:\Users\fzheng\source\repos\co\base\win/atomic.h(190): error C3861: '_InterlockedAnd64': identifier not found
C:\Users\fzheng\source\repos\co\base\win/atomic.h(206): error C3861: '_InterlockedXor64': identifier not found
C:\Users\fzheng\source\repos\co\base\win/atomic.h(222): error C3861: '_InterlockedOr64': identifier not found
C:\Users\fzheng\source\repos\co\base\win/atomic.h(238): error C3861: '_InterlockedAnd64': identifier not found
C:\Users\fzheng\source\repos\co\base\win/atomic.h(254): error C3861: '_InterlockedXor64': identifier not found
C:\Users\fzheng\source\repos\co\base\win/atomic.h(270): error C3861: '_InterlockedExchange64': identifier not found

Question about set_cloexec

inline void set_cloexec(sock_t fd) {
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_EXCL);
}

O_EXCL or FD_CLOEXEC ?

arm gcc编译器无法通过编译, 需要将char 改成int8_t

index 9d2a6e3..c09f622 100644
--- a/src/hash/base64.cc
+++ b/src/hash/base64.cc
@@ -3,7 +3,7 @@
static const char* entab =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

-static const char detab[256] = {
+static const int8_t detab[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,

能否给个CMAKE的编译脚本

能否给个CMAKE的编译脚本,最好在alpine的环境下也能编译通过,github上很多库我在制作alpine镜像时候都碰到各种问题

关于 `thread_ptr` 的疑问

@idealvin 你好。

按我的理解,当 thread_ptr 的对象,例如 foo,以 std::ref(foo) 的方式传进线程函数之后,子线程是无法获取父线程设置的指针值的。也就是说,任何一个线程要使用 foo,都必须现在线程内设置 foo 指向的对象才能使用。

既然如此,为什么不在每个线程里分别使用 std::unique_ptr 呢?使用 thread_ptr 的好处在哪里?

关于LruMap的疑问

// The key is not inserted if it already exists.
void insert(const K& key, const V& value) {
      auto r = _kv.insert(std::make_pair(key, value));
      if (!r.second) return;

      _kl.push_front(key);
      _ki[key] = _kl.begin();

      if (_kv.size() > _capacity) {
          K k = _kl.back();
          _kl.pop_back();
          _kv.erase(k);
          _ki.erase(k);
      }
}

当缓存中已有key时,insert不会有任何操作,如果我想更新一个key的value时该怎么办,并且_kl中的顺序也要改变。

Lru 实现

插入发现存在是不是调整一下位置到头部?
list用了2个使用一个效率会更好一点?
//一般插入实现大致这样

void put(const Key& key,const Value& value){
	const auto iter = _cache.find(key);
	if(iter!= _cache.end()){
		// 找到了就更新value,并提取到最前面
		iter->second->value = value;
		//move iter->second to _keys' begin postion
		_keys.splice(_keys.begin(),_keys,iter->second);
		return;
	}
	_keys.emplace_front(key,value);
	_cache[key] = _keys.begin();
	resize();
}

Document that fastring is not thread-safe

The implementation of fastring is not thread-safe. That’s fine, but people might get in trouble if they don’t know this, since std::string is thread-safe. So it would be good to point this out in the documentation.

(Making fastring thread safe is probably not a good idea. I’ve read that std::string used to use ref-counting and copy-on-write the way yours does, but the atomic operations or mutexes needed to make it thread-safe hurt performance a lot, and it’s actually faster for it to always copy.)

关于Json::Value::operator[]的疑问

https://github.com/idealvin/co/blob/110eadde2c89dffa259a161c100cd4161253441f/base/json.cc#L15

正常访问一个objectmember时,应该先调用has_member()来进行判断。但看上面函数的代码,如果直接使用[]来访问相关member,这里的逻辑似乎是打算支持这种行为?

如果不支持的话,21&22行的意义何在呢?
如果支持的话,接下来访问其它member或者调用str()就会出错了。如以下代码:

#include "co/json.h"

int main() {
  auto v = json::parse("{\"name\": \"tiger\"}");
  v["n"];
  printf("%s\n", v["name"].str().c_str());
  return 0;
}

输出结果是null

udpsocket co::close无法让co::recvfrom跳出等待

co::close 触发了del_event(ev)
但是co::recvfrom等待的EV_read 消息订阅被删除,但是recvfrom仍然在等待。

解决方法:
1、或许可以加入EV_close/EV_ignore之类的事件。
2、IoEvent加入多事件绑定,同时绑定EV_read和EV_close/EV_ignore。

release下执行vs2015 logTest文件报错

FLOG << "This is FLOG (fatal).. " << 23;
执行这句的时候报错
0x00007FFFD0CCE91E (ucrtbase.dll) (**.exe 中)处有未经处理的异常: 请求了严重的程序退出。
想问下是什么情况导致的?
代码和设置没有做任何更改

`json::Value::str()`不能正确地序列化某些浮点数值

当JSON字符串中含有1.0之类的数值时,json::Value::str()会将其序列化为1,这与原来该字段的类型不符,如果多次依次执行序列化、反序列化操作,会导致断言。

版本:Commit 95535b3 之前都有此现象
系统:Debian 10(Windows未测试)
内核:5.4.0-1-amd64

示例

#include <stdio.h>

#include "base/json.h"

fastring s = "{\"value\": 12.0}";

int main(int argc, char** argv) {
    auto j1 = json::parse(s);
    auto j2 = json::parse(j1.str());

    printf("j1 value: %f\n", j1["value"].get_double());
    printf("j2 value: %f\n", j2["value"].get_double());

    return 0;
}

执行结果

j1[0]: 12.000000
j_test: ./base/json.h:226: double json::Value::get_double() const: Assertion `this->is_double()' failed.
error: execv(/home/tiger/Codes/co/build/linux/x86_64/release/j_test) failed(-1)!

原因:序列化操作使用了fast::dtoa(),而fast::dtoa()在输出浮点时使用了Conversion Specifier g,这会导致尾部的0会被移除。这样就造成了类型不一致的问题。

random.h中的一些疑惑

uint32_t next() {
static const uint32_t M = 2147483647L; // 2^31-1
static const uint64_t A = 16385; // 2^14+1

// Computing _seed * A % M.
uint64_t p = _seed * A;
_seed = static_cast<uint32_t>((p >> 31) + (p & M));
if (_seed > M) _seed -= M;

return _seed;
}

其中if (_seed > M) _seed -= M; 这行是不是多余的, 因为M本来就是uint32_t的最大值, 上面一行强转uint32_t之后不能大于M, if这条语句是不可能走到的

rpc test失败

环境:vs2019
问题:运行rpc test程序时出现错误map/set iterators incompatible

dtoa很慢

做了一个测试,发现对于double类型转为字符串,速度超级慢

const size_t N = 10000000;

template<typename T>
void benchPrintf(const char* fmt) {

    TimeStamp start = TimeStamp::now();
    char buf[32];
  
    for (size_t i = 0; i < N; ++i)
        snprintf(buf, sizeof buf, fmt, (T)(i));

    TimeStamp end = TimeStamp::now();
    printf("benchPrintf %f\n", timeDifference(end, start));
}

template<typename T>
void benchStringStream() {

    TimeStamp start = TimeStamp::now();
    std::ostringstream os;

    for (size_t i = 0; i < N; ++i) {
        os << (T)(i);
        os.seekp(0, std::ios_base::beg);
    }

    TimeStamp end = TimeStamp::now();
    printf("benchStringStream %f\n", timeDifference(end, start));
}

template<typename T>
void benchStream() {

    TimeStamp start = TimeStamp::now();
    FStream os;
    for (size_t i = 0; i < N; ++i) {
        os << (T)(i);
        os.clear();
    }
    TimeStamp end = TimeStamp::now();
    printf("benchStream %f\n", timeDifference(end, start));
}

int main()
{

  puts("int");
  benchPrintf<int>("%d");
  benchStringStream<int>();
  benchStream<int>();

  puts("double");
  benchPrintf<double>("%.12g");
  benchStringStream<double>();
  benchStream<double>();

  puts("int64_t");
  benchPrintf<int64_t>("%" PRId64);
  benchStringStream<int64_t>();
  benchStream<int64_t>();

  puts("void*");
  benchPrintf<void*>("%p");
  benchStringStream<void*>();
  benchStream<void*>();
}

JSON实现不符合ECMA-404

string没有实现\uxxxx形式的unicode转义,以及\b \f的转义。

看实现实在没法看出来为什么会比rapidJSON性能高,而rapidJSON甚至都用上了SIMD优化,麻烦给出benchmark?

关于 C++11 特性的考虑

目前看来这些代码并没有按照 C++11 前和 C++11 开始条件编译。假如这是有意的,那么我认为有些细节实现应当继续改进:

  • def.h 应当直接使用 <cstdint> 或者 <stdint.h> 。其他代码应该直接使用 (u)intN_t 以减少冲突。
  • 应该使用标准的 thread_local 代替 __thread
  • 原子对象应当使用 <atomic>
  • swap 函数和移动特殊成员函数应当加上 noexcept
    (以及其他可能存在的问题)

co:Event wait()不带参数,无法唤醒

#include "co/co.h"
#include "co/log.h"
#include "co/time.h"

co::Event ev;

DEF_bool(wait_alway, true, "false: wait for timeout, true wait alway");
void f2(){
    CLOG << "f2() start";
    bool r = true;
    if (FLG_wait_alway) {
        ev.wait();
    } else {
        r = ev.wait(1*1000);
    }
    CLOG << "f2() end: " << r;
}

void f3() {
    CLOG << "f3() start";
    ev.signal();
    CLOG << "f3() end";
}

int main(int argc, char** argv) {
    flag::init(argc, argv);
    log::init();
    go(f2);
    sleep::ms(100);
    go(f3);

    sleep::ms(2*1000);
    return 0;
}

运行结果1:
./test wait_alway=false

f2() start
f3() start
f3() end
f2() end: true

运行结果1:
./test wait_alway=true

f2() start
f3() start
f3() end

fastring: 多线程问题与内存管理问题

  1. fastring 类的引用计数未使用原子对象。这显然会造成多线程同时修改时的数据竞争。希望作者注明这种设计是否有意的。
  2. fastring 类的内存分配、释放函数是不能替换的。我认为替换全局的 operator newoperator delete 是在一定应用条件下提高性能的做法,但 fastring 并不能从中受益。

关于定长整数类型

本库引入了定长整数类型别名。但有一些处理让我觉得困惑:

  • fastring 的内部引用计数类需要假定
    unsigned int 的长度;
  • Random 的整个操作看起来需要依赖标准整数类型的长度;
  • 以及可能存在的其他依赖标准整数类型长度的实现。

这些地方是不是直接使用定长整数类型别名更好?

其次,本库的定长整数类型依赖了 <stdint.h> 。它是 C99/C++11 起的标准库头文件,即使 MSVC 也支持。
是否考虑在此方面移除对 _MSC_VER 的检测?

Error: Unrecognized Exception

将co log编入dll,使用c#调用,.log文件中会缺失很多条log,并且会产生.fatal文件,.fatal文件事例如下:

1216 22:30:33] Error: Unrecognized Exception
D:\Project\co\base\stack_trace\StackWalker.cpp (1096): StackWalker::ShowCallstack
D:\Project\co\base\stack_trace\stack_trace_win.cpp (203): `anonymous namespace'::StackTraceImpl::on_exception
00007FFBA96B78D8 (ntdll): (filename not available): RtlInitializeCriticalSection
00007FFBA965D4FA (ntdll): (filename not available): RtlWalkFrameChain
00007FFBA965BE9A (ntdll): (filename not available): RtlRaiseException
00007FFBA671A388 (KERNELBASE): (filename not available): RaiseException
00007FFB54122413 (mono-2.0-bdwgc): (filename not available): mono_native_thread_set_name
00007FFB541D3B60 (mono-2.0-bdwgc): (filename not available): mono_thread_set_manage_callback
00007FFB541DC685 (mono-2.0-bdwgc): (filename not available): mono_threads_set_shutting_down
00007FFB541D57E8 (mono-2.0-bdwgc): (filename not available): mono_threads_set_shutting_down
00007FFB541D5576 (mono-2.0-bdwgc): (filename not available): mono_threads_set_shutting_down
00007FFBA8134034 (KERNEL32): (filename not available): BaseThreadInitThunk
00007FFBA96C3691 (ntdll): (filename not available): RtlUserThreadStart

1216 22:30:33] Error: Unrecognized Exception
D:\Project\co\base\stack_trace\StackWalker.cpp (1096): StackWalker::ShowCallstack
D:\Project\co\base\stack_trace\stack_trace_win.cpp (203): `anonymous namespace'::StackTraceImpl::on_exception
00007FFBA96B78D8 (ntdll): (filename not available): RtlInitializeCriticalSection
00007FFBA965D4FA (ntdll): (filename not available): RtlWalkFrameChain
00007FFBA965BE9A (ntdll): (filename not available): RtlRaiseException
00007FFBA671A388 (KERNELBASE): (filename not available): RaiseException
00007FFB54122413 (mono-2.0-bdwgc): (filename not available): mono_native_thread_set_name
00007FFB541D3B60 (mono-2.0-bdwgc): (filename not available): mono_thread_set_manage_callback
00007FFB541D8B0B (mono-2.0-bdwgc): (filename not available): mono_threads_set_shutting_down
00007FFB541DB231 (mono-2.0-bdwgc): (filename not available): mono_threads_set_shutting_down
00007FFB541D57E8 (mono-2.0-bdwgc): (filename not available): mono_threads_set_shutting_down
00007FFB541D5576 (mono-2.0-bdwgc): (filename not available): mono_threads_set_shutting_down
00007FFBA8134034 (KERNEL32): (filename not available): BaseThreadInitThunk
00007FFBA96C3691 (ntdll): (filename not available): RtlUserThreadStart

windows 上 dll 调试模式下程序崩溃,Debug Assertion Failed!

只要我使用 co::sleep 函数就会报错
co 使用cmake 编译得 然后引入了 头文件 和LIB文件
使用官方的 client 代码示例

`

sock_t fd = co::tcp_socket();
struct sockaddr_in addr;
co::init_ip_addr(&addr, "127.0.0.1", 7788);
co::connect(fd, &addr, sizeof(addr), 3000);
co::set_tcp_nodelay(fd);
char buf[8] = { 0 };
for (int i = 0; i < 7; ++i) {
    co::sleep(1000);
    LOG << "send ping";
    co::send(fd, "ping", 4);
    co::recv(fd, buf, 4);
    LOG << "recv " << buf;
}
co::close(fd);

`

co::connect 填写第4个参数会报错 崩溃
co::sleep 也会报错 崩溃

错误提示
Debug Assertion Failed!

Program: E:\fiber\exiecheng\coroutine\Debug\testdll.exe
File: D:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.26.28801\include\xtree
Line: 229

Expression: map/set iterators incompatible

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.

(Press Retry to debug the application)

是否有意向将install后的库名以及目录名由base改为co?

目前执行xmake install后,会将头文件放在base目录下,静态库被命名为libbase.abase这个名字太普通了,不够将库与程序内部的名字区分开。既然项目名叫co,何不将头文件放在include/co目录下,且库名为libco.alibco.so

这个动静有点大,但从长远来看,我觉得有必要来执行这个改动。

fastring 的原位构造函数

现版本的 fastring 拥有直接利用未被管理的内存的构造函数。看起来此构造函数得到使用的地方看起来很少(目前只注意到此处),而且写法上没有体现原位构造的特征。

我个人认为把它改成 static 成员函数(如 fastring::from_raw_buffer )或者友元自由函数(如 friend raw_buffer_to_fastring )会让用户更谨慎而安全地使用。

另外,或许只把此功能作为内部实现而非作为公开 API 也是一种选择。

如何更改配置的值

类似于文档的这种 日志输出的位置,日志文件名字,应该如何设置呢?

`//日志打印输出的位置
DEF_string(log_dir, "../log", "Log dir, will be created if not exists");
//日志文件名
DEF_string(log_file_name, "acl_log", "name of log file, using exename if empty");
//日志打印级别
DEF_int32(min_log_level, 0, "write logs at or above this level, 0-4 (debug|info|warning|error|fatal)");
//输出到终端
DEF_bool(cout, true, "also logging to terminal");

DEF_int32(co_sched_num, 100, "协程栈大小,每个调度线程都会分配一个栈,调度线程内的协程共用这个栈。");
DEF_int32(co_max_recv_size, 2, "一次能接收的最大数据长度,默认为 1M,超过此大小,分批接收。");
DEF_int32(co_max_send_size, 2, "一次能发送的最大数据长度,默认为 1M,超过此大小,分批发送");`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.