• Feeds

  • Linux Load编程竞赛

    Linux load average的意思就是说 目前有ready的进程 但是cpu都在满,然后这个数是一分钟的平均值。公式:loadvg = tasks running + tasks waiting (for cores) + tasks blocked. 让CPU满是最简单的方式

    为了更好理解load average,Tim某天在群征集一段代码使load average最高。于是乎,群友纷纷出手。

    Erlang版

    [~]$ cat load10
    #!/usr/bin/env escript
    %% -- erlang --
    %%! -smp enable -sname load10
    main(_) ->
    I = erlang:system_info(scheduler_id),
    random(5).
    
    random(I) when I > 10 ->
    random(I+1);
    random(I) ->
    spawn(fun() -> random(I+1) end),
    random(I+1).
    

    此代码将Linux load跑到了10-20,取得了领先

    Shell版

    #!/bin/sh
    for((i=0;i<10;i++));do
    {
    for((j=0;j<1000000000000;j++));do echo '1'>>1; done
    }&
    done
    

    Ruby

    ruby -e "require 'thread';t = Mutex.new;10.times {fork {10000000.times{t.synchronize {x=Time.now}}}}"
    

    Java版

    import java.io.*;
    
    public class LoadTest {
    
      public static void main(String[] args) throws IOException, InterruptedException {
          int count = 1000;
          for (int i = 0; i < count; i++) {
              final Thread t = new Thread(new Runnable() {
                  public void run() {
                      try {
                          while (true) {
                              RandomAccessFile file = new RandomAccessFile("/tmp/test.bin", "rw");
                              file.seek(1024 * 1024 * 500);
                              file.write(1);
                              file.close();
                          }
                      } catch (IOException e) {
                      }
                  }
              });
              t.start();
          }
          Thread.currentThread().join();
      }
    }
    

    C语言版

    void main () {
    int i=0;
    for (i = 0; i < 1000; i++) {
    if (fork () > 0) {
    continue;
    }
    while (1) ;
    }
    getchar();
    }
    

    此版本远远超过了上面的Erlang版本,将load拉到1000+

    Java版本2

    public class Test {
    
       public static void main(String[] args) {
           for (int i = 0; i < 1000; i++) {
               new Thread() {
                   @Override
                   public void run() {
                       while (true) ;
                   }
               }.start();
           }
       }
    }
    

    此版本和上面C版本效果类似

    部分讨论:

    不对呀,这个方法以前不行
    CentOS 6吧[惊讶]
    CentOS 5
    有几个版本有bug,cpu的hz拿的不对,load特别低,7就好了[坏笑]

    Java版本3

    写两类线程,一类进行lockObject wait, 一类进行lockObject notifyall。 cpu上下文切换消耗 竞争激烈。Load能很高。

    public class LoadHighDemo {
    
       public static void main(String[] args) throws Exception {
           LoadHighDemo demo = new LoadHighDemo();
           demo.runTest();
       }
    
       private void runTest() throws Exception {
           Object[] locks = new Object[5000];
           for (int i = 0; i < 5000; i++) {
               locks[i] = new Object();
               new Thread(new WaitTask(locks[i])).start();
               new Thread(new NotifyTask(locks[i])).start();
           }
       }
    
       class WaitTask implements Runnable {
    
           private Object lockObject = null;
    
           public WaitTask(Object obj) {
               lockObject = obj;
           }
    
           public void run() {
               while (true) {
                   try {
                       synchronized (lockObject) {
                           lockObject.wait(new java.util.Random().nextInt(10));
                       }
                   } catch (Exception e) {;
                   }
               }
           }
       }
    
       class NotifyTask implements Runnable {
    
           private Object lockObject = null;
    
           public NotifyTask(Object obj) {
               lockObject = obj;
           }
    
           public void run() {
               while (true) {
                   synchronized (lockObject) {
                       lockObject.notifyAll();
                   }
                   try {
                       Thread.sleep(new java.util.Random().nextInt(5));
                   } catch (InterruptedException e) {
                   }
               }
           }
       }
    }
    

    上物理机把5000个线程改成更多,如50000也行。
    直接while true改5000应该能更多……
    我的应该能一直上涨, load 1000, 2000, 3000

    可以试试parkNanos(1)

    刚才卡了。。。
    看来不能在本机上跑

    Python版

    把5分钟 load avg 稳定在1024了
    在本群感到了一种情怀。。。

    #!/usr/bin/env python
    import os
    import sys
    import time
    
    def load_add_1():
    time.sleep(30)
    fd=os.open("test.txt",os.O_CREAT|os.O_RDWR|os.O_SYNC, 0644)
    for i in xrange(10000*100):
    os.write(fd," "*100)
    sys.exit(0)
    
    for i in xrange(8192):
    if os.fork() == 0:
    load_add_1()
    

    此版本将load跑到8192

    C语言版本2

    https://gist.github.com/hongqn/37cdfde04d0c5a03fede

    #include <unistd.h>
    #include <stdio.h>
    
    #define LOAD 16384
    
    int main() {
    int i;
    char s[256];
    
    for (i=0; i<LOAD; i++) {
    if (vfork()) {
    return 0;
    }
    }
    scanf("%s", s);
    return 0;
    }
    

    macbook 上 virtualbox 里一个 2G mem 单 core cpu 的虚机就可以轻松达到16,000
    这个的原理是通过 vfork 产生指定个数的 D 状态进程,从而提高 load

    Vfork() differs from fork in that the child borrows the parent’s memory and thread of control until a call to execve(2) or an exit (either by a call to exit(2) or abnormally.) The parent process is suspended while the child is using its resources.
    vfork 的子进程只要不 execve 或者退出,父进程就一直挂着(在D状态)。这里就是让最后一个子进程用 scanf 等输入

    通过以上题目,你是看到了热闹,还是看到了门道?

     

    如想及时阅读Tim Yang的文章,可通过页面右上方扫码订阅最新更新。

    « | »

    4 Comments  »

    1. fatpp

      c 语言版本二中, if(){return } 这个不是会把程序挂掉么?

    2. Kroderia

      贡献一个

      #/bin/bash
      yes

    3. guojun

      楼上不行吧,死循环一直输出y负载肯定上不去。

    4. 我曾经碰到一个想创业的人,他说他现在给人打工,一个月能挣多少钱,如果去创业,这边打工的钱就没有了,这样的话他还房贷就会很困难。他还说他即使去创业,也不一定能成功,但他又很想去做,问我怎么办。我说你回去做个梦,第二天早上醒来问问自己,你想不想把这个梦变成真的。如果想,那就什么都不要想了,赶紧去做。我还跟他说,如果过了五分钟,你还能说出这个梦,那就说明你内心真的特别想做这件事,那你就去做,再也别犹豫。如果五分钟以后你说不出什么来了,那你就彻底把它忘了吧,就当没这回事,你还老老实实地过日子。

    Leave a Comment