如何使用多处理创建 nntplib 对象

How to create nntplib objects using Multiprocessing

在创建与 NNTP 服务器的连接时,尝试 2 天让多处理工作。目标:尽可能快地建立一堆连接(比如 50 个)。由于在 for 循环中建立连接可能很慢(例如最多 10 秒),我想使用多处理将它们全部 'at once'。创建连接后,它们保持打开状态,因为在未来的某个多处理部分将发出 10,000+ 请求,依赖于类似的原则。

部分代码简化:

#!/usr/bin/env python3

import sys
import ssl
from nntplib import NNTP_SSL
from multiprocessing import Pool 

def MakeCon(i, host, port):
    context = ssl.SSLContext(ssl.PROTOCOL_TLS)
    s = NNTP_SSL(host, port=port, ssl_context=context, readermode=True)
    print('created connection', i)  # print to see progress
    sys.stdout.flush()
    return s

def Main():
    host = 'reader.xsnews.nl'
    port = 563
    num_con = 4

    y=MakeCon(1, host, port).getwelcome()  #request some message from NNTP host to see if it works
    print(y)

    # the actual part that has the issue:
    if __name__ == '__main__':

        cons = range(num_con)
        s = [None] * num_con
        pool = Pool()
        for con in cons:
            s[con]=pool.apply_async(MakeCon, args=(con, host, port))
        pool.close

        print(s[1])
        for con in cons:
            t=s[con].getwelcome()  #request some message from NNTP host to see if it works
            print(t)

        print('end')

Main()

显示与 NNTP 服务器等的连接有效,但我无法将连接提取到某个对象中,我可以将其与 nntplib 选项结合使用。我会说我对 python 没有那么多经验,尤其是没有多处理。

您的方法存在一些不同的问题。最大的是在不同的进程中创建连接,然后将它们发送到主进程,这将不起作用。这是因为每个连接都会打开一个套接字,而套接字是不可序列化的(可拾取的),因此不能在进程之间发送。

即使它有效,使用 .apply_sync() 也不是正确的方法。最好使用 .map(),其中 return 是函数调用的直接输出(相对于 .apply_sync(),return 是 return 的对象可以提取值)。

但是,在当前情况下,程序是 I/O 绑定的,而不是 CPU 绑定的,在这些情况下,线程与多进程一样工作,因为 GIL不会阻止执行。因此,更改为线程而不是多处理并从 .apply_sync() 更改为 .map() 给出以下解决方案:

#!/usr/bin/env python3

import sys
import ssl
from nntplib import NNTP_SSL
from multiprocessing.pool import ThreadPool 

def MakeCon(i, host, port):
    context = ssl.SSLContext(ssl.PROTOCOL_TLS)
    s = NNTP_SSL(host, port=port, ssl_context=context, readermode=True)
    print('created connection', i)  # print to see progress
    sys.stdout.flush()
    return s

def Main():
    host = 'reader.xsnews.nl'
    port = 563
    num_con = 4

    y=MakeCon(1, host, port).getwelcome()  #request some message from NNTP host to see if it works
    print(y)
    return con

    cons = range(num_con)
    s = [None] * num_con
    pool = ThreadPool()
    s=pool.map(lambda con: MakeCon(con, host, port), cons)
    pool.close

if __name__ == "__main__":
    Main()

不过,有一点忠告。小心创建过多的连接,因为这样做可能会耗尽资源,因此服务器可能无法很好地查看连接。

此外,如果您要使用不同的连接来获取文章,这些调用也应该在不同的线程中完成。

并且,作为最后的评论,与使用线程相同的效果是使用 asyncio。然而,您可能需要研究一段时间才能熟练使用。