【问题标题】:When doing network programming, is there a rule of thumb for determining how many threads to use?在进行网络编程时,是否有确定使用多少线程的经验法则?
【发布时间】:2013-04-29 16:48:15
【问题描述】:

假设我有一个包含 1000 个唯一 URL 的列表,我需要打开每个 URL,并且 assert 页面上有一些东西。按顺序执行此操作显然是一个糟糕的选择,因为大多数情况下程序将处于空闲状态,只是等待响应。因此,添加到线程池中,每个工作人员从主Queue 读取,并打开一个 url 进行检查。我的问题是,我要把游泳池弄多大?它是基于我的网络带宽还是其他一些指标?是否有任何经验法则,或者只是为了找到有效尺寸而反复试验?

这更像是一个理论问题,但这是我正在使用的代码的基本轮廓。

if __name__ == '__main__':
    #get the stuff I've already checked
    ID = 0
    already_checked = [i[ID] for i in load_csv('already_checked.csv')]

    #make sure I don't duplicate the effort
    to_check = load_csv('urls_to_check.csv')
    links = [url[:3] for url in to_check if i[ID] not in already_checked]

    in_queue = Queue.Queue()
    out_queue = Queue.Queue()

    threads = []
    for i in range(5):
        t = SubProcessor(in_queue, out_queue)
        t.setDaemon(True)
        t.start()
        threads.append(t)

    writer = Writer(out_queue)
    writer.setDaemon(True)
    writer.start()

    for link in links:
        in_queue.put(link)

【问题讨论】:

  • 是 I/O 绑定还是处理器绑定?如果它受 I/O 限制,请尝试使用与处理器内核数相同的线程数。
  • @RobertHarvey 我认为 I/O 绑定的东西可能会使用比内核更多的线程数,因为 CPU 在实际 IO 发生时大部分时间处于空闲状态(在这种情况下,等待网络响应)。我是不是误会了?
  • I/O 绑定意味着您正在等待 I/O。因此,除非您在处理器旋转 I/O 时有更多工作要做,否则更多线程毫无意义。
  • 如果线程主要进行网络 I/O,没有重要的磁盘 I/O 或数字运算,您可能可以并行运行所有 1000 个线程。如果前 999 个 URL 访问非常慢的网络服务器,那么至少第 1000 个会很快返回。但是,我认为这是没有很好答案的问题之一。

标签: python multithreading threadpool


【解决方案1】:

您最好的选择可能是编写一些代码,使用您指定的线程数运行一些测试,并查看有多少线程产生最佳结果。有太多变量(处理器速度、总线速度、线程开销、内核数量以及代码本身的性质),我们无法猜测。

【讨论】:

  • DNS 查找和 HTTP GET 都非常受 I/O 限制。解析页面不是。尝试一些不同的值,是的。
【解决方案2】:

我的经验(使用 .NET,但它应该适用于任何语言)是 DNS 解析最终成为限制因素。我发现最多可以支持 15 到 20 个并发请求。 DNS 解析通常非常快,但有时可能需要数百毫秒。如果没有一些自定义 DNS 缓存或其他快速解决问题的方法,我发现它平均大约需要 50 毫秒。

如果您可以进行多线程 DNS 解析,那么在现代硬件(四核机器)上肯定可以处理 100 个或更多并发请求。您的操作系统如何处理这么多单独的线程完全是另一个问题。但是,正如您所说,这些线程大多只在等待响应。另一个考虑因素是这些线程正在做多少工作。如果它只是下载一个页面并寻找特定的东西,100 个线程可能在合理范围内。前提是“查找”不仅仅涉及解析 HTML 页面。

其他注意事项涉及您正在访问的唯一域的总数。如果这 1,000 个唯一 URL 都来自不同的域(即 1,000 个唯一域),那么您遇到最坏的情况:每个请求都需要 DNS 解析(缓存未命中)。

如果这 1000 个 URL 仅代表 100 个域,那么您将只有 100 个缓存未命中。前提是你机器的DNS缓存是合理的。但是,您还有另一个问题:使用多个并发请求访问同一台服务器。如果您发出许多(有时“许多”被定义为“两个或更多”)并发请求,某些服务器会非常不高兴。或者短时间内请求过多。因此,您可能必须编写代码来防止对同一服务器的多个或超过 X 个并发请求。它可能会变得复杂。

防止多请求问题的一种简单方法是按域对 URL 进行排序,然后确保来自同一域的所有 URL 都由同一线程处理。从性能的角度来看,这并不理想,因为您经常会发现一两个域的 URL 比其他域多得多,并且您最终会发现大多数线程都结束了,而只有少数线程正在阻塞繁忙的域。您可以通过检查数据并相应地分配线程的工作项来缓解这些问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多