绕过os线程限制的编程策略?

时间:2010-01-02 22:19:11

标签: python multithreading

场景:我们有一个python脚本,可以同时检查数千个代理。 该程序使用每个代理1个线程来加速该过程。当它到达1007线程时,脚本因线程限制而崩溃。 我的解决方案是:一个全局变量,当线程产生时递增,并在线程结束时递减。产生线程的函数监视变量,以便不达到限制。
你的解决方案是什么,朋友?

感谢您的回答。

11 个答案:

答案 0 :(得分:5)

您希望使用select module进行非阻塞I / O.

有几种不同的具体技术。 select.select应该适用于每个主要平台。还有其他更高效的变体(如果您同时检查数万个连接可能很重要),但您需要为特定平台编写代码。

答案 1 :(得分:4)

我以前遇到过这种情况。只需创建一个任务池,并生成固定数量的线程,这些线程运行无限循环,从池中抓取任务,运行它,然后重复。基本上,您正在实现自己的线程抽象并使用操作系统线程来实现它。

这确实有缺点,主要的一点是,如果你的任务长时间阻止,他们可以阻止执行其他任务。但它确实允许您创建无限数量的任务,仅受内存限制。

答案 2 :(得分:3)

Python是否具有任何类型的异步IO功能?这将是首选的答案IMO - 为每个出站连接产生一个额外的线程并不像有一个有效事件驱动的线程那样整洁。

答案 3 :(得分:2)

使用不同的流程和管道传输数据。在python中使用线程非常蹩脚。据我所知,即使您拥有多核处理器,它们实际上并不是并行运行......但也许它已在python3中修复。

答案 4 :(得分:2)

  

我的解决方案是:一个全局变量,当线程产生时会增加,并在线程完成时递减。产生线程的函数监视变量,以便不达到限制。

标准方法是让每个线程在循环中获得下一个任务,而不是在处理一个之后死亡。这样您就不必跟踪线程数,因为您只需触发固定数量的线程。作为奖励,您可以节省线程创建/销毁。

答案 5 :(得分:2)

计数信号量应该可以解决问题。

from socket import *
from threading import *

maxthreads = 1000
threads_sem = Semaphore(maxthreads)

class MyThread(Thread):
    def __init__(self, conn, addr):
        Thread.__init__(self)
        self.conn = conn
        self.addr = addr
    def run(self):
        try:
            read = conn.recv(4096)
            if read == 'go away\n':
                global running
                running = False
            conn.close()
        finally:
            threads_sem.release()

sock = socket()
sock.bind(('0.0.0.0', 2323))
sock.listen(1)
running = True
while running:
    conn, addr = sock.accept()
    threads_sem.acquire()
    MyThread(conn, addr).start()

答案 6 :(得分:1)

确保你的线程在被使用或使用线程池之后被正确销毁,尽管我认为它们在Python中没有那么有效

见这里:

http://code.activestate.com/recipes/203871/

答案 7 :(得分:1)

使用select模块或类似的库很可能是一种更有效的解决方案,但这需要更大的体系结构更改。

如果你只想限制线程数,那么全局计数器应该没问题,只要你以线程安全的方式访问它。

答案 8 :(得分:1)

小心最小化默认线程堆栈大小。至少在Linux上,默认限制会严重限制创建的线程数。 Linux将一大块进程虚拟地址空间分配给堆栈(通常为10MB)。 300个线程x 10MB堆栈分配= 3GB虚拟地址空间专用于堆栈,而在32位系统上,您有3GB限制。你可以用更少的东西逃脱。

答案 9 :(得分:1)

Twisted非常适合这个问题。有关编写客户端的教程,请参阅http://twistedmatrix.com/documents/current/core/howto/clients.html

如果您不介意使用备用Python实现,Stackless具有轻量级(非本机)线程。我所知道的唯一一家公司就是CCP - 他们在客户端和服务器上将它用于游戏中的tasklet。您仍然需要使用Stackless执行异步I / O,因为如果线程阻塞,则进程阻塞。

答案 10 :(得分:1)

正如另一个线程中所提到的,为什么要为每个单独的操作生成一个新线程?这是一个经典的生产者 - 消费者问题,不是吗?根据您的看法,代理检查员可能是消费者或生产者。

无论如何,解决方案是使“任务”的“队列”进行处理,并使循环中的线程检查是否有更多任务要在队列中执行,如果没有,请等待预定义的间隔,然后再次检查。

您应该使用一些锁定机制(即信号量)保护您的队列,以防止竞争条件。

这真的不那么难。但它需要一点思考才能做到正确。祝你好运!