分类 工作&技术 下的文章

前几天我还在夸他家好用,结果闹了半天是这么回事。。。
当然,大家又可以欢呼,在蒸馏上我们遥遥领先了。 这可不是乱说,抖阴和头条上这是主旋律。

图片_20250131232449.jpg

甲骨文免费机要求cpu不能长期闲置,否则可能会认为机器空闲而回收。所以,有了下面的要求。 这是个很简单的程序了,显然是交给AI,今天无聊,我同时让几个AI来写想来对比一下。我很惊讶的是比较结果。

省流: DeepSeek > Claude > ChatGpt > Llama * claude和gpt的排名不是太确定,第一和最后是很确定的。
代码核心是怎么控制cpu占用,下面我就只贴出来相关代码,其它省略了。

prompt: 帮我写段linux的c代码,cpu.c,它是让cpu空转的。它可以跟一个参数,比如 ./cpu 10 ,表示占用10%的cpu资源。 需要多cpu多线程下也能工作。 程序运行后fork到后台,永远执行。
*都只是向ai发起第一次询问时取这条结果,没有再次的交互。

ChatGPT:
仅仅是sleep一下,这个并不会消耗cpu资源。

// 单线程函数,用于控制 CPU 占用率
void* control_cpu(void* arg) {
    int usage = *(int*)arg;
    struct timespec busy_time, idle_time;

    // 计算忙碌时间和空闲时间
    busy_time.tv_sec = 0;
    busy_time.tv_nsec = usage * 10 * 1000 * 1000; // 使用率对应的纳秒数
    idle_time.tv_sec = 0;
    idle_time.tv_nsec = (100 - usage) * 10 * 1000 * 1000; // 空闲时间对应的纳秒数

    while (running) {
        // 模拟忙碌
        clock_nanosleep(CLOCK_MONOTONIC, 0, &busy_time, NULL);
        // 模拟空闲
        clock_nanosleep(CLOCK_MONOTONIC, 0, &idle_time, NULL);
    }

    return NULL;
}

Claude:
试图通过一个循环for (long long i = 0; i < 10000000L * cpu_load_percentage; i++)来消耗CPU,确实这可以消耗,但是,它完全控制不了运行时间,因为各CPU性能不一样。这是大学第一学期C语言课就会知道的常识。

void *busy_work(void *arg) {
    while (should_run) {
        // Busy wait
        for (long long i = 0; i < 10000000L * cpu_load_percentage; i++) {
            __asm__ volatile ("nop");
        }
        // Sleep to control total CPU usage
        usleep(10000 * (1.0 - cpu_load_percentage));
    }
    return NULL;
}

LLAMA:
错误与Claude一样,更扯的是,它居然想只*1000而已,太低估CPU的计算能力了。

void* cpu_idle(void* arg) {
    int cpu_usage = *(int*)arg;
    int sleep_time = 100 - cpu_usage;

    while (1) {
        // 占用 CPU 资源
        for (int i = 0; i < cpu_usage * 1000; i++) {
            volatile int x = i * i;
        }

        // 休眠
        usleep(sleep_time * 1000);
    }

    return NULL;
}

DeepSeek:
今天的测试胜利者,完全出乎我的预料。
四个AI中,它是唯一正确编码的。

void* cpu_busy_loop(void* arg) {
    struct timespec start, now;
    long elapsed_ns;
    long sleep_ns;
    long busy_ns;

    // 计算每个周期中忙碌和睡眠的时间
    busy_ns = (target_cpu_usage * NS_PER_SEC) / 100;
    sleep_ns = NS_PER_SEC - busy_ns;

    while (running) {
        clock_gettime(CLOCK_MONOTONIC, &start);

        // 忙碌循环
        while (1) {
            clock_gettime(CLOCK_MONOTONIC, &now);
            elapsed_ns = (now.tv_sec - start.tv_sec) * NS_PER_SEC + (now.tv_nsec - start.tv_nsec);
            if (elapsed_ns >= busy_ns) {
                break;
            }
        }

        // 睡眠
        struct timespec sleep_time;
        sleep_time.tv_sec = sleep_ns / NS_PER_SEC;
        sleep_time.tv_nsec = sleep_ns % NS_PER_SEC;
        nanosleep(&sleep_time, NULL);
    }

    return NULL;
}

早上起来没事,让ai写了一个telegram的ai机器人,我的主要诉求其实是要一个简单的封装的包来调用ai。不知道gayhub上有没有类似的,但自己调教的肯定是最符合自己习惯的。github上的开源项目往往都是太大而复杂了。
现在的封装是这样的,我觉得蛮好的,简单直观。

systemPrompts := []string{
    "现在假定你是一个电脑专家,你在回答用户问题。",
        "除了套话和一般性对话外,你不要回答任何其它专业的问题"
}

aiClient := ai.NewAIClient(      //兼容openai,deepseek等。
    "https://api.groq.com/openai/v1/chat/completions",          // API 地址
    "123456",   // API 密钥
    "llama-3.3-70b-versatile",                                  // 模型名称
    4096,                                                       // 最大 Token 数量
    systemPrompts,                                              // 系统提示
)        

response, err := aiClient.AskAI(chatSession, update.Message.Text)   //输入一段文字得到ai回应

以前一直用github copilot,不过我一个月可能只有10天码代码,其它20天在摸鱼,$10虽然不多,但浪费也不好啊。虽然现在copilot出了免费版,不过一共2000次提示,这写一天代码就没了,毕竟一次回车敲下去它就来一大段。
这段时间老是看到deepseek的软文,号称与chatgpt 4o不相上下。水平不知道,但价格确实是屠夫级。试试看吧。

deepseek.jpg

docker默认是通过DOCKER链处理forward等规则,因此,系统的常规(input)链对它限制是无效的,简单说就是docker突破了iptables,docker开放的端口不受iptables的限制。(当然,仅仅是input链,但常规我们也只处理input)

我以前是简单的/etc/docker/daemon.json中禁用docker的iptables自动规则管理来解决问题,不过最近遇到一个情况,因为docker应用需要对访问者ip做dns反向解析,因此,禁用了iptables自动规则后,docker无法访问外网(缺乏相应的转发和nat规则),引起反向解析失败。解析失败没事,但一直要到超时错,就是整整60秒才能响应,这个就无法接受了。 * 以前似乎这么做没问题,就这次不行,而且是多台机器上都一样,不知道是不是docker升级了啥的。

既然不能简单关闭docker的iptables托管,那就只能是在系统的iptables层级上想办法了。
查了资料,docker提供了一个DOCKER-USER链,它是前置于docker的,因此,在它上面打主意就可以了。
下面的例子就是,允许特定ip(1.1.1.1)访问docker上的nginx的80端口,除此之外的所有docker端口的访问均被拒绝。(本机,即input不受影响)

root@xxxxxxxx:~# cat /etc/iptables/rules.v4 
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [1039:304535]
:DOCKER-USER DROP [0:0]              #docker-user链,它运行于docker链之前,因此可过滤docker的流量。
#常规的规则(input链),根据情况自己写了。这里的话是开放22的访问。
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
#DOCK-USER链规则开始
-A DOCKER-USER -o eth0 -p tcp -j ACCEPT   #允许docker的向外访问。 eth0需要改成外网网卡的实际名称。
-A DOCKER-USER -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT  #允许已建立的连接继续通信
-A DOCKER-USER -i docker0 -o docker0 -j ACCEPT             #允许各个docker间的通信
-A DOCKER-USER -i br-+ -o br-+ -j ACCEPT        #允许各个docker间的通信

-A DOCKER-USER ! -i docker0 -s 1.1.1.1 -p tcp -m tcp --dport 80 -j ACCEPT   #默认规则为禁止,所以这个是白名单,允许1.1.1.1访问本地的80端口。     
....    对外开放的服务规则一直加在这里就好了

-A DOCKER-USER ! -i docker0 -p tcp -m tcp -j DROP  #禁止除白名单外的所有请求

COMMIT