dask入门教程
并行计算库Dask官方教程(中文翻译)
dask和numpy的计算对比
并行计算:这是一台计算机的概念,即一台计算机中多个处理器被组织起来,大任务下达的时候,将大任务分成若干个小任务,然后分配给若干个处理器进行运算。
并行计算(Parallel Computing)是指同时使用多种计算资源解决计算问题的过程,是提高计算机系统计算速度和处理能力的一种有效手段。它的基本思想是用多个处理器来协同求解同一问题,即将被求解的问题分解成若干个部分,各部分均由一个独立的处理器来并行计算。并行计算系统既可以是专门设计的、含有多个处理器的超级计算机,也可以是以某种方式互连的若干台的独立计算机构成的集群。通过并行计算集群完成数据的处理,再将处理的结果返回给用户。
并行计算可分为时间上的并行和空间上的并行。
时间上的并行:是指流水线技术,比如说工厂生产食品的时候步骤分为:
1. 清洗:将食品冲洗干净。
2. 消毒:将食品进行消毒处理。
3. 切割:将食品切成小块。
4. 包装:将食品装入包装袋。
如果不采用流水线,一个食品完成上述四个步骤后,下一个食品才进行处理,耗时且影响效率。但是采用流水线技术,就可以同时处理四个食品。这就是并行算法中的时间并行,在同一时间启动两个或两个以上的操作,大大提高计算性能。
空间上的并行:是指多个处理机并发的执行计算,即通过网络将两个以上的处理机连接起来,达到同时计算同一个任务的不同部分,或者单个处理机无法解决的大型问题。
比如小李准备在植树节种三棵树,如果小李1个人需要6个小时才能完成任务,植树节当天他叫来了好朋友小红、小王,三个人同时开始挖坑植树,2个小时后每个人都完成了一颗植树任务,这就是并行算法中的空间并行,将一个大任务分割成多个相同的子任务,来加快问题解决速度。
分布式计算:这个一组计算机的概念,通过计算机网络连接起来,大任务下达的时候,将大任务分成若干个小任务,然后分配给若干个计算机进行运算。
研究如何把一个需要非常巨大的计算能力才能解决的问题分成许多小的部分,然后把这些部分分配给许多计算机进行处理,最后把这些计算结果综合起来得到最终的结果。
最近的分布式计算项目已经被用于使用世界各地成千上万位志愿者的计算机的闲置计算能力,通过因特网,可以分析来自外太空的电讯号,寻找隐蔽的黑洞,并探索可能存在的外星智慧生命;可以寻找超过1000万位数字的梅森质数;也可以寻找并发现对抗艾滋病病毒的更为有效的药物。这些项目都很庞大,需要惊人的计算量,仅仅由单个的电脑或是个人在一个能让人接受的时间内计算完成是绝不可能的。
显然,分布式计算非常强调计算机网络中的计算机合作,并行式计算强调一个计算机的多个处理器合作。
(1)并行计算投入更多机器,数据大小不变,计算速度更快,而分布式计算投入更多的机器,能处理更大的数据;
(2)并行计算必须要求时间同步,而分布式计算没有时间限制。
Dask是一个用于分析计算的灵活的并行计算库。
pip install dask
python -m pip install "dask[array]"
python -m pip install "dask[distributed]"
python -m pip install "dask[dataframe]"
#dask求解10个数的平均值
import dask.array as da
import numpy as np
x=np.arange(10000000)
#chunks表示划分时每块的大小(大数据超过内存容量时,需要对数据进行按块划分)
y=da.from_array(x,chunks=(100,))
print(y)
print(y.mean())
print(y.mean().compute())
首先在命令行窗口执行dask-scheduler命令,得到以下输出:
其中,tcp://192.168.1.4:8786可以做为当前电脑的url地址,在同一局域网下,可以在另一主机上通过client方法进行主机的连接。
(1)client内容为空或者为127.0.0.1.8786时,默认启动本地调度工作程序(此时客户端和本地客户端应建立连接),客户端将自身注册为默认的Dask调度程序。
from dask.distributed import Client
if __name__ == "__main__":
client = Client()
a = client.map(lambda x:x**2,range(10))
b = client.map(lambda x:x+1,a)
c = client.map(lambda x:-x,b)
re = client.submit(sum, c).result()
print(re)
(2)当client不为空,为另一主机的url时:
这时首先在当前客户机输入命令:
dask-worker 192.168.1.4:8786
此时将scheduler和workers绑定在一起。
结果表示客户机与主机连接成功,此时就能够分布式利用不同主机间运行程序。
from dask.distributed import Client
if __name__ == "__main__":
client = Client("tcp://192.168.1.4:8786")
a = client.map(lambda x:x**2,range(10))
b = client.map(lambda x:x+1,a)
c = client.map(lambda x:-x,b)
re = client.submit(sum, c).result()
print(re)
(1)submit(方法,数值), 对数值执行某种方法。
(2)若想显示出来直观的结果,则调用result()方法。
from dask.distributed import Client
def inc(x):
return x+1
if __name__ == "__main__":
client = Client("tcp://192.168.1.4:8786")
x1 = client.submit(inc,10)
print(x1)
print(x1.result())
x2 = client.map(inc,range(2))
print(x2)
print(client.gather(x2))
x3 = client.submit(sum,x2)
print(x3)
print(x3.result())
输出如下:
<Future: pending, key: inc-d3f5af4d5bb89c246f58e2a8fa150373>
11
[<Future: pending, key: inc-9e50b1e0389d7a9c0a888ae20ae00cae>,
<Future: pending, key: inc-d78d089440e3814014b4f8e92775a40e>]
[1, 2]
<Future: pending, key: sum-36d98f2f40c36fc256240b1a9c0feadd>
3
(3)对于map()方法来说,map(方法,数值列表),通过遍历数值列表的数值进行数值计算,想直观的看到map()运行后的结果,需要调用client.garher(参数值)方法。
(4)对于submit和map等函数运行结果中都出现了key关键词,可以试验并且发现,当调用的函数是纯函数时,所得的key应是完全一样的,这就是dask中避免重复计算所才用的策略,当出现重复的计算时,只需要比较key的值就能利用旧的结果,而不需要重新计算。
from dask.distributed import Client
from operator import add
if __name__ == "__main__":
client = Client("tcp://192.168.1.4:8786")
x = client.submit(add,1,2)
y = client.submit(add,1,2)
print(x.key)
print(y.key)
(5)当函数不纯时,众所周知的就是random函数,每次执行的值都不同,但是函数是不变的,所以在dask中加入了一个参数:pure,当pure=False时,禁用以上功能。
from dask.distributed import Client
import numpy as np
if __name__ == "__main__":
client = Client("tcp://192.168.1.4:8786")
x = client.submit(np.random.random,3,pure=False)
y = client.submit(np.random.random,3,pure=False)
print(x.key)
print(y.key)
print(x.result())
print(y.result())
from dask.distributed import Client
import dask.dataframe as dd
if __name__ == "__main__":
client = Client("192.168.1.4:8786")
df = dd.read_csv("data.csv")
df = client.persist(df)
client.publish_dataset(my_data=df)
my_data是把数据集命一个新的名称,在与调度机相连的任意客户机都能访问此数据集。
from dask.distributed import Client
if __name__ == "__main__":
client = Client("tcp://192.168.1.4:8786")
print(client.list_datasets())
df = client.get_dataset("my_data")