Os.sched_getapherity(0)与os.cpu_count()

问题描述

所以,我知道标题中这两种方法的区别,但不知道实际意义。

据我所知:如果您使用的NUM_Worker多于实际可用的内核,您将面临巨大的性能下降,因为您的操作系统不断来回切换以保持并行。我不知道这是不是真的,但我是从某个比我聪明的人那里读到的。

os.cpu_count()的文档中写着:

返回系统的CPU数量。如果未确定,则返回NONE。此数量不等于 当前进程可以使用。可以获得可用的CPU数量 WITH len(os.sched_getapherity(0))

因此,如果某个进程可以使用的CPU比系统中的CPU多,那么我想知道系统指的是什么。

我只想安全高效地实现multiprocessing.pool功能。所以我的问题总结如下:

NUM_WORKERS = os.cpu_count() - 1
# vs.
NUM_WORKERS = len(os.sched_getaffinity(0)) - 1

-1是因为我发现,如果我尝试在处理数据的同时工作,我的系统延迟会小很多。


解决方案

如果您的任务是纯100%受CPU限制的,即只做计算,那么显然,如果进程池大小大于计算机上可用的CPU数量,则不会/不会获得任何好处。但是,如果有I/O的混合,进程将放弃CPU,等待I/O完成(或者,例如,从网站返回URL,这需要相对较长的时间),该怎么办?在我看来,在这种情况下,如果进程池大小超过os.cpu_count(),您是否无法实现更高的吞吐量,这一点我不清楚。

更新

以下是演示这一点的代码。这段代码使用的是进程,使用线程处理可能是最好的选择。我的台式机上有8个内核。该程序只需同时检索54个URL(在本例中为并行检索)。向程序传递一个参数,即要使用的池的大小。遗憾的是,仅创建其他进程就会产生初始开销,因此如果您创建了太多进程,节省的成本就会开始下降。但是,如果任务长时间运行并且有大量I/O,那么创建进程的开销最终将是值得的:

from concurrent.futures import ProcessPoolExecutor, as_completed
import requests
from timing import time_it

def get_url(url):
    resp = requests.get(url, headers={'user-agent': 'my-app/0.0.1'})
    return resp.text


@time_it
def main(poolsize):
    urls = [
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
        'https://ibm.com',
        'https://microsoft.com',
        'https://google.com',
    ]
    with ProcessPoolExecutor(poolsize) as executor:
        futures = {executor.submit(get_url, url): url for url in urls}
        for future in as_completed(futures):
            text = future.result()
            url = futures[future]
            print(url, text[0:80])
            print('-' * 100)

if __name__ == '__main__':
    import sys
    main(int(sys.argv[1]))

8进程:(我的核数):

func: main args: [(8,), {}] took: 2.316840410232544 sec.

16个进程:

func: main args: [(16,), {}] took: 1.7964842319488525 sec.

24个进程:

func: main args: [(24,), {}] took: 2.2560818195343018 sec.

相关文章