dask.distributed LocalCluster与线程和进程之间的区别

时间:2019-09-02 16:53:39

标签: python dask dask-distributed

以下LocalCluster的{​​{1}}配置之间有什么区别?

dask.distributed

Client(n_workers=4, processes=False, threads_per_worker=1)

它们都在任务图上有四个线程,但是第一个有四个工作线程。那么,让多个工作人员充当线程而不是一个工作人员具有多个线程有什么好处呢?

编辑:只是为了澄清,我知道进程,线程和共享内存之间的差异,因此,这个问题更多地针对这两个客户端的配置差异。

3 个答案:

答案 0 :(得分:1)

当您使用process = False时,就是在限制群集只能通过计算机体系结构工作。

from dask.distributed import Client

# The address provided by processes=False is a In-process transport address. 
# This is used to perform communication between threads 
# Scheduler and workers are on the same machine.
client = Client(processes=False)
client
<Client: scheduler='inproc://10.0.0.168/31904/1' processes=1 cores=4>

# The address provided on processes=True is tcp protocol. 
# This is a network address. You can start workers from others machines
# just pointing the scheduler address to this tcp address 
# (All machines must be on the same network).
client = Client(processes=True)
client
<Client: scheduler='tcp://127.0.0.1:53592' processes=4 cores=4>

答案 1 :(得分:1)

您在这里混淆了两件事:

  • 进程数和线程数之间的平衡,不同的混合有利于不同的工作负载。每个工作人员更多的线程意味着更好地共享内存资源并避免了序列化;更少的线程和更多的进程意味着更好地避免了GIL

  • 使用processes=False,调度程序和工作程序都作为线程在与客户端相同的进程中运行。同样,它们将共享内存资源,您甚至不必在客户端和调度程序之间序列化对象。但是,您将有很多线程,并且客户端的响应速度可能会降低。这通常用于测试,因为可以直接自省调度程序和工作对象。

答案 2 :(得分:0)

我从Victor和Martin的答案中得到了启发,对我进行了更深入的研究,因此,这里是我的理解的深入总结。 (无法在评论中这样做)

首先,请注意,此版本的dask中的调度程序打印输出不是很直观。 processes实际上是工作线程数,cores实际上是所有工作线程中线程的总数。

第二,值得一提的是Victor关于TCP地址以及添加/连接更多工作程序的评论。我不确定是否可以通过processes=False将更多工作线程添加到群集中,但是我认为答案可能是肯定的。

现在,考虑以下脚本:

from dask.distributed import Client

if __name__ == '__main__':
    with Client(processes=False) as client:  # Config 1
        print(client)
    with Client(processes=False, n_workers=4) as client:  # Config 2
        print(client)
    with Client(processes=False, n_workers=3) as client:  # Config 3
        print(client)
    with Client(processes=True) as client:  # Config 4
        print(client)
    with Client(processes=True, n_workers=3) as client:  # Config 5
        print(client)
    with Client(processes=True, n_workers=3,
                threads_per_worker=1) as client:  # Config 6
        print(client)

这会为我的笔记本电脑(4核)在dask 2.3.0版中产生以下输出:

<Client: scheduler='inproc://90.147.106.86/14980/1' processes=1 cores=4>
<Client: scheduler='inproc://90.147.106.86/14980/9' processes=4 cores=4>
<Client: scheduler='inproc://90.147.106.86/14980/26' processes=3 cores=6>
<Client: scheduler='tcp://127.0.0.1:51744' processes=4 cores=4>
<Client: scheduler='tcp://127.0.0.1:51788' processes=3 cores=6>
<Client: scheduler='tcp://127.0.0.1:51818' processes=3 cores=3>

这是我对配置之间差异的理解:

  1. 调度程序和所有工作程序在客户端进程中作为线程运行。 (如Martin所说,这对于自省很有用。)由于既未提供worker的数量,也不提供线程/ worker的数量,因此dask调用其函数nprocesses_nthreads()来设置默认值(使用{{1 }},1个进程和线程数等于可用的内核数。
  2. 与1相同,但是由于给出了processes=False,因此线程/工作人员被轻而易举地选择,以使线程总数等于核心数(即1)。同样,打印输出中的n_workers并不完全正确-实际上是工作程序的数量(在这种情况下,实际上是线程)。
  3. 与2相同,但是由于processes不能平均划分为内核数,因此dask选择2个线程/每个工人过量使用而不是不足。
  4. 客户,调度程序和所有工作程序都是独立的进程。 Dask选择默认数量的工作程序(等于内核,因为它<= 4)和默认线程/工作程序数(1)。
  5. 与5相同的进程/线程配置,但由于与3相同的原因,总线程数超额预定。
  6. 这表现出预期。