kcp icon indicating copy to clipboard operation
kcp copied to clipboard

what is the best practices with ikcp_check

Open easy-chu opened this issue 7 years ago • 14 comments

I need to handle 10k connections, but ikcp_update consumes too much CPU. I know the ikcp_check is a better choice, but I don't know how to use it. I read all the issues and wiki, I found that many people have the same problem with me. If anyone knows how to use it, please answer here. a. If I use ikcp_check, do I still need to call ikcp_update repeatly ? b. Do I need to manually modify the value of kcp->updated ? Otherwise, the logic of ikcp_update and ikcp_check seems contradictory. c. If I use ikcp_check, do I need to increase the interval time ? Otherwise how does it achieve the effect of reducing the call (the return value of ikcp_check is shorter than interval). If anyone knows the answer, please tell me, thanks very much. I believe many people also need it !

easy-chu avatar Mar 16 '18 13:03 easy-chu

Seems to me like you would want

While (1) {
    Sleep(ikcp_check()); // which returns milliseconds to next update
    Ikcp_update();
    // handle input and output
}

But honestly I just read the code, haven’t started using Kcp yet.

danlapid avatar Mar 30 '18 21:03 danlapid

对于C点, 我也有这个疑问, CHECK机制是怎么节省CPU的呢? 我测试的结果是interval是10毫秒时候, 依然在疯狂的update, 作者能回答下这个问题吗?

fofewyoung avatar Jan 10 '19 07:01 fofewyoung

ikcp_check 是返回下一次需要调用 ikcp_update 的时间(如果没有 ikcp_input 的话),简单点:

while (1) {
  current = clock();
  ikcp_update(current);
  ts = ikcp_check();
  Sleep(ts - current);
}

实际的话,你需要同时管理 N 个 kcp 对象的 ikcp_check 返回时间,放到 timer里调度:

  1. 如果到时间了,那么执行 ikcp_update,并且重新 check,确定下一次时间,放入 timer 调度。
  2. 如果有数据包 ikcp_input 进来了,那么 ikcp_update,再 check 重新调度。

这么简单。

skywind3000 avatar Jan 10 '19 10:01 skywind3000

我的疑问是: CPU为什么会节省? 以interval=10ms为例 你的写法: while (1) { current = clock(); ikcp_update(current); ts = ikcp_check(); Sleep(ts - current); }

我们服务器的写法, 没有使用ikcp_check(伪码) setTimer(10, ()=>{ current = clock(); ikcp_update(current); } )

你的写法里ikcp_check返回的结果不会超过10MS, CPU省在哪里呢

fofewyoung avatar Feb 22 '19 02:02 fofewyoung

我疑问的来源是, 最佳实践中提到: “使用该方法,原来在处理2000个 kcp连接且每 个连接每10ms调用一次update,改为 check机制后,cpu从 60%降低到 15%” 我所不明白的是: 原来是10ms调用一次update, 难道加入check机制后会变成超过10MS一次吗,我看到的ikcp_check的源码返回值是不会超过一个interval的? 望指正

fofewyoung avatar Feb 22 '19 02:02 fofewyoung

哇哈哈,也正是我的疑问,按照文档的说法根本不可能节省CPU。如果改成以下这样才有可能节省(但逻辑不一定正确,可以探讨):

while(10ms loop)
{
    current = clock();
    next = ikcp_check(current);

    // !!重点!!
    if(current == next)
        ikcp_update(current);
}

ldcsaa avatar Mar 07 '19 04:03 ldcsaa

这个我也感觉很奇怪. 从ikcp_check代码来看的确起不到降低CPU的作用

除非我代码是死循环不带延时的调用update, 那调用ikcp_check才能达到比之前的CPU占用低的目的, 如果我本身代码里面就有延时 10 ms, 那即使调用ikcp_check, 根据ikcp_check返回值我还是顶多只能sleep 10ms...................

0xhellord avatar Mar 08 '19 06:03 0xhellord

有了 ikcp_check,interval 就不需要订到 10ms 那么小了,kcp 就变成 tickless 了,你用timer,将多个 kcp 对象的调度,均摊再 1 个 interval 里面,就是这个意思。

skywind3000 avatar Mar 08 '19 07:03 skywind3000

有了 ikcp_check,interval 就不需要订到 10ms 那么小了,kcp 就变成 tickless 了,你用timer,将多个 kcp 对象的调度,均摊再 1 个 interval 里面,就是这个意思。

@skywind3000 还是有些疑问:首先需要确定是一个timer处理所有连接,还是每个连接有自己的timer? 1、如果是一个timer处理所有连接,势必会造成连接串行遍历,如果连接数较多(如1万个),加上每个连接send/recv/update等方法都需要同步,会不会造成更大的延时?另外,这种方式下interval值也不可能设置得太大。 2、如果每个连接有自己的timer,这时每个连接就自己管自己,不必遍历了。如:interval设置为1秒,以后根据ikcp_check的返回值确定下次update的时间。 3、还有一个问题:如果ikcp_check返回值为当前时间,是不是要继续循环调用check/update直到返回值大于当前时间为止?

现状是没有任何ikcp_check的示例代码,如果有示例给大家参考的话相信疑问会少很多。

ldcsaa avatar Mar 09 '19 10:03 ldcsaa

每个链接都有自己的一个 timer id,使用 linux 时间轮算法,O(1) 的时钟调度。

我自己的网络协议栈是公司代码,没法开源,请理解。

skywind3000 avatar Mar 09 '19 11:03 skywind3000

感觉有点纠结了,interval不能设置太长, 但这种机制必然有个问题, 太长不及时,太短无端耗费CPU。

halx99 avatar May 27 '19 12:05 halx99

Kcp这几个函数或者变量确实令人迷惑。 interval 似乎并不是真的是 interval,因为 似乎并不是控制外部时钟频率的,而是内部用来比对的一个阈值。 update和check到底如何配合使用也是个问题。 而且就目前来看kcp不是线程安全的,但是调用update和check似乎又必须要开个timer线程调用。 总之Kcp的理念是不错。不过要用好,还是需要了解更多的细节,并且需要自己搞不少轮子,摸索最佳实践。

sgf avatar Oct 02 '20 11:10 sgf

有了 ikcp_check,interval 就不需要订到 10ms 那么小了,kcp 就变成 tickless 了,你用timer,将多个 kcp 对象的调度,均摊再 1 个 interval 里面,就是这个意思。

从ikcp_update代码来看, 只有current>=ts_flush才会调用ikcp_flush. 这样调用ikcp_check还有什么意义呢?反正ikcp_flush的调用间隔始终是interval时间啊。

tpunix avatar Dec 01 '20 15:12 tpunix

试着回答一下楼上的问题, timer的触发事件改成动态的,减少了timer的触发次数,当没有input或者send时,可以等待较长时间再触发timer,就节省了cpu

aolm2 avatar May 17 '21 11:05 aolm2