OSX上的应用程序不能产生超过2048个线程

时间:2015-06-02 21:05:31

标签: linux multithreading macos rust

我在OSX上有一个Rust应用程序启动大量线程,如下面的代码所示,但是,在查看我的OSX版本允许通过{{1}创建多少个最大线程数之后}命令,我可以看到它是sysctl kern.num_taskthreads,它解释了为什么我不能超过2048个线程。

我如何才能超越这个硬限制?

kern.num_taskthreads: 2048

2 个答案:

答案 0 :(得分:7)

在开始之前,我建议您阅读C10K problem。当你进入这个规模时,你需要记住更多的事情。

话虽如此,我建议看看mio ......

  

Rust的轻量级IO库,专注于在OS抽象上添加尽可能少的开销。

具体来说,mio提供了一个事件循环,它允许您处理大量连接而不会产生线程。不幸的是,我不知道当前支持mio的HTTP库。你可以创建一个并成为Rust社区的英雄!

答案 1 :(得分:1)

不确定这会有多大帮助,但我试图创建一个小的线程池来创建连接,然后通过一个通道将它们发送到事件循环进行读取。

我确定这段代码可能非常糟糕,但无论如何都是这样的例子。它使用Hyper库,就像你提到的那样。

extern crate hyper;

use std::io::Read;
use std::thread;
use std::thread::{JoinHandle};
use std::sync::{Arc, Mutex};
use std::sync::mpsc::channel;

use hyper::Client;
use hyper::client::Response;
use hyper::header::Connection;

const TARGET: i32 = 100;
const THREADS: i32 = 10;

struct ResponseWithString {
    index: i32,
    response: Response,
    data: Vec<u8>,
    complete: bool
}

fn main() {
    // Create a client.
    let url: &'static str = "http://www.gooogle.com/";

    let mut threads = Vec::<JoinHandle<()>>::with_capacity((TARGET * 2) as usize);
    let conn_count = Arc::new(Mutex::new(0));
    let (tx, rx) = channel::<ResponseWithString>();

    for _ in 0..THREADS {
        // Move var references into thread context
        let conn_count = conn_count.clone();
        let tx = tx.clone();

        let t = thread::spawn(move || {
            loop {
                let idx: i32;
                {
                    // Lock, increment, and release
                    let mut count = conn_count.lock().unwrap();
                    *count += 1;
                    idx = *count;
                }
                if idx > TARGET {
                    break;
                }

                let mut client = Client::new();

                // Creating an outgoing request.
                println!("Creating connection {}...", idx);
                let res = client.get(url)                       // Get URL...
                                .header(Connection::close())    // Set headers...
                                .send().unwrap();               // Fire!

                println!("Pushing response {}...", idx);
                tx.send(ResponseWithString {
                    index: idx,
                    response: res,
                    data: Vec::<u8>::with_capacity(1024),
                    complete: false
                }).unwrap();
            }
        });
        threads.push(t);
    }

    let mut responses = Vec::<ResponseWithString>::with_capacity(TARGET as usize);
    let mut buf: [u8; 1024] = [0; 1024];
    let mut completed_count = 0;
    loop {
        if completed_count >= TARGET {
            break; // No more work!
        }

        match rx.try_recv() {
            Ok(r) => {
                println!("Incoming response! {}", r.index);
                responses.push(r)
            },
            _ => { }
        }

        for r in &mut responses {
            if r.complete {
                continue;
            }

            // Read the Response.
            let res = &mut r.response;
            let data = &mut r.data;
            let idx = &r.index;

            match res.read(&mut buf) {
                Ok(i) => {
                        if i == 0 {
                            println!("No more data! {}", idx);
                            r.complete = true;
                            completed_count += 1;
                        }
                        else {
                            println!("Got data! {} => {}", idx, i);
                            for x in 0..i {
                                data.push(buf[x]);
                            }
                        }
                    }
                Err(e) => {
                    panic!("Oh no! {} {}", idx, e);
                }
            }
        }
    }
}