Dask源码剖析是一个专栏,更多章节请点击文章列表查看。后续我会更新更多内容上来。
Dask 介绍
Dask是一款用于分析计算的灵活并行计算库。
Dask由两部分组成:
调度:针对计算优化的动态任务调度。这与Airflow,Luigi,Celery或Make类似,但针对交互式计算工作负载进行了优化。
数据结构:“大数据”集合, 像并行数组,数据框和列表一样,它们将通用接口(如NumPy,Pandas或Python迭代器)扩展到大于内存或分布式环境。 这些并行集合运行在动态任务调度器之上。
前期准备
想要对开源项目的代码有深入的理解,剖析源码,首先要“用”过这个开源项目,即作为用户,使用这个组件,知道它的特性,调用方式。最好能再踩过一些坑并通过debug形式进入源码走读一下。否则完全不了解一个库,何谈剖析源码?
所以第一步,请在实际工作中用Dask与distributed库。当然,如果你用过spark或celery等其他分布式任务调度框架,或者用过pandas、numpy,也可以根据以往的经验用dask写一些简单的demo,了解一些特性。其中官方的dask-tutorial就是很好的帮手,不妨克隆下来试用一下。github地址:https://github.com/dask/dask-tutorial
搭建阅读环境
配置一个python环境
可以用conda或venv创建一个python解释器环境,环境要求:
- 尽量Python3.6以上吧
- 不要装dask、distributed
新建文件夹并克隆项目
这一步看似简单,却是调试源码的关键,因为dask社区是把项目分成了dask(数据结构定义与任务定义)distributed(分布式任务管理与执行器)等多个部分的,要跨项目调试代码,首先要把他们都clone到同一个文件夹下,并通过pycharm或vscode等打开。
例如我现在文件夹结构是这样的:
然后在pycharm里,把dask、distributed标记成source-root。vscode类似,把这两个项目加到PYTHONPATH下。这样就可以源码调试了
另外咱们可以把教程也克隆下来,通过教程的例子debug到源码里,帮助理解。
安装依赖库
这时候我们看下dask的setup.py中的依赖库:
extras_require = {
"array": ["numpy >= 1.13.0", "toolz >= 0.8.2"],
"bag": [
"cloudpickle >= 0.2.2",
"fsspec >= 0.6.0",
"toolz >= 0.8.2",
"partd >= 0.3.10",
],
"dataframe": [
"numpy >= 1.13.0",
"pandas >= 0.23.0",
"toolz >= 0.8.2",
"partd >= 0.3.10",
"fsspec >= 0.6.0",
],
"distributed": ["distributed >= 2.0"],
"diagnostics": ["bokeh >= 1.0.0"],
"delayed": ["cloudpickle >= 0.2.2", "toolz >= 0.8.2"],
}
总结下来就是:
numpy>=1.13.0
toolz>=0.8.2
cloudpickle >= 0.2.2
fsspec >= 0.6.0
partd >= 0.3.10
distributed 咱们从源码调试,不装了。
bokeh 可视化用的,先不看了,也不用装。
然后咱们pip install 上述的这些库,也可以保存成一个requirements.txt里,用pip install -r requirements.txt来批量安装。注意pip用上面搭建的新python环境的,不要有dask、distributed库。
再看看distributed的依赖:
click >= 6.6
cloudpickle >= 1.3.0
contextvars;python_version<‘3.7’
dask >= 2.9.0
msgpack >= 0.6.0
psutil >= 5.0
sortedcontainers !=2.0.0, !=2.0.1
tblib >= 1.6.0
toolz >= 0.8.2
tornado >= 5;python_version<‘3.8’
tornado >= 6.0.3;python_version>=‘3.8’
zict >= 0.1.3
pyyaml
setuptools
这里去掉dask库,因为咱们也是要用源码调试的。
另外再安装jupyter,新版的pycharm、vscode都支持在ide中打开、debug notebook了,所以咱们可以直接用dask官方的教程作为debug的原料。
配置启动入口
如果只关注dask数据结构,不需要distributed,那么可以直接自定义脚本debug就好啦。但是咱们用dask不就是想要用它分布式的特性吗?所以还要在IDE下,配置distributed库的scheduler和worker的启动参数:
以pycharm为例:
scheduer可以无参数启动
入口点在:
opensource\distributed\distributed\cli\dask_scheduler.py
worker需要配置一些参数:
入口点在:
opensource\distributed\distributed\cli\dask_worker.py
参数行填scheudler的IP:PROT,我这是192.168.3.100:8786,然后是单进程单线程的worker起来,便于debug。 --nthreads=1就行。
环境测试
OK,到此为止,都配置好了,可以启动scheduler和worker,发起一个简单的调用试一下,看看是否会有日志输出了 。
先用debug启动刚配置的scheduler、再用debug启动刚刚配置的worker。
我们再新建一个delay_demo.py(也可以用dask-tutorial的01_dask.delayed.ipynb)并执行。
from time import sleep
from dask import delayed
from dask.distributed import Client
def inc(x):
sleep(1)
return x + 1
def add(x, y):
sleep(1)
return x + y
if __name__ == '__main__':
client = Client(address='192.168.3.100:8786')
x = delayed(inc)(1)
y = delayed(inc)(2)
z = delayed(add)(x, y)
print(z)
print(z.compute())
client.close()
对应会看到worker、scheduler、client的日志内容。如果能看到scheduer输出:
distributed.scheduler - INFO - -----------------------------------------------
distributed.http.proxy - INFO - To route to workers diagnostics web server please install jupyter-server-proxy: python -m pip install jupyter-server-proxy
distributed.scheduler - INFO - -----------------------------------------------
distributed.scheduler - INFO - Clear task state
distributed.scheduler - INFO - Scheduler at: tcp://192.168.3.100:8786
distributed.scheduler - INFO - dashboard at: :8787
distributed.scheduler - INFO - Register worker <Worker 'tcp://192.168.3.100:52974', name: tcp://192.168.3.100:52974, memory: 0, processing: 0>
distributed.scheduler - INFO - Starting worker compute stream, tcp://192.168.3.100:52974
distributed.core - INFO - Starting established connection
distributed.scheduler - INFO - Receive client connection: Client-c60b227b-bab1-11ea-9dc4-e0d55e23eea2
distributed.core - INFO - Starting established connection
distributed.core - INFO - Event loop was unresponsive in Scheduler for 3.89s. This is often caused by long-running GIL-holding functions or moving large chunks of data. This can cause timeouts and instability.
distributed.scheduler - INFO - Remove client Client-c60b227b-bab1-11ea-9dc4-e0d55e23eea2
distributed.scheduler - INFO - Remove client Client-c60b227b-bab1-11ea-9dc4-e0d55e23eea2
distributed.scheduler - INFO - Close client connection: Client-c60b227b-bab1-11ea-9dc4-e0d55e23eea2
demo输出:
Delayed('add-66132714-45e9-44d6-87ef-80bb01cfcdda')
5
说明调通了,我们可以开始啃代码拉!!