使用Dask,Distributed进行大规模并行搜索操作

时间:2017-08-31 14:45:34

标签: python distributed dask dask-distributed

我在Kubernetes和AWS上测试自动调整Dask分布式实现时创建了一个演示问题,我不确定我是否正确解决了这个问题。

我的方案给出了一个字符串的md5哈希(代表密码)找到原始字符串。我遇到了三个主要问题。

A)参数空间庞大,试图创建一个2.8211099e + 12成员的dask包导致内存问题(因此您将在下面的示例代码中看到' explode'功能) 。

B)早期发现清洁退出。我认为使用take(1, npartitions=-1)会实现这一目标,但我不确定。最初我提出了一个例外raise Exception("%s is your answer' % test_str),它虽然有效,但感觉很糟糕"

C)鉴于这种情况持续很长时间,有时工人或AWS盒子死亡,最好存储进度?

示例代码:

import distributed
import math
import dask.bag as db
import hashlib 
import dask
import os

if os.environ.get('SCHED_URL', False):
    sched_url = os.environ['SCHED_URL']
    client = distributed.Client(sched_url)
    versions = client.get_versions(True)
    dask.set_options(get=client.get)

difficulty = 'easy'

settings = {
    'hard': (hashlib.md5('welcome1'.encode('utf-8')).hexdigest(),'abcdefghijklmnopqrstuvwxyz1234567890', 8),
    'mid-hard': (hashlib.md5('032abgh'.encode('utf-8')).hexdigest(),'abcdefghijklmnop1234567890', 7),
    'mid': (hashlib.md5('b08acd'.encode('utf-8')).hexdigest(),'0123456789abcdef', 6),
    'easy': (hashlib.md5('0812'.encode('utf-8')).hexdigest(),'0123456789', 4)
}

hashed_pw, keyspace, max_guess_length = settings[difficulty]

def is_pw(guess):
    return hashlib.md5(guess.encode('utf-8')).hexdigest() == hashed_pw 

def guess(n):
    guess = ''
    size = len(keyspace)
    while n>0 :
        n -= 1
        guess += keyspace[n % size];
        n = math.floor(n / size);
    return guess

def make_exploder(num_partitions, max_val):
    """Creates a function that maps a int to a range based on the number maximum value aimed for
        and the number of partitions that are expected.
        Used in this code used with map and flattent to take a short list 
        i.e 1->1e6 to a large one 1->1e20 in dask rather than on the host machine."""
    steps = math.ceil(max_val / num_partitions)
    def explode(partition):
        return range(partition * steps, partition * steps + steps)
    return explode


max_val = len(keyspace) ** max_guess_length # How many possiable password permutation
partitions = math.floor(max_val / 100) 
partitions = partitions if partitions < 100000 else 100000 # split in to a maximum of 10000 partitions. Too many partitions caused issues, memory I think.
exploder = make_exploder(partitions, max_val) # Sort of the opposite of a reduce. make_exploder(10, 100)(3) => [30, 31, ..., 39]. Expands the problem back in to the full problem space.

print("max val: %s, partitions:%s" % (max_val, partitions))

search = db.from_sequence(range(partitions), npartitions=partitions).map(exploder).flatten().filter(lambda i: i <= max_val).map(guess).filter(is_pw)

search.take(1,npartitions=-1)

我发现&#39; easy&#39;在当地运作良好,中等难度&#39;适用于我们的6到8 * m4.2xlarlar AWS集群。但到目前为止还没有hard工作。

1 个答案:

答案 0 :(得分:3)

  

A)参数空间庞大,试图创建一个2.8211099e + 12成员的dask包导致内存问题(因此您将在下面的示例代码中看到&#39; explode&#39;功能)

这很大程度上取决于您如何将元素整理到包中。如果每个元素都在它自己的分区中,那么是的,这肯定会杀死所有东西。 1e12分区非常昂贵。我建议保留数千或数万的分区数。

  

B)早期发现清洁退出。我认为使用take(1,npartitions = -1)可以达到这个目的,但我不确定。最初我提出了异常提升异常(&#34;%s是你的答案&#39;%test_str)哪个有效,但觉得&#34;脏&#34;

如果你想要这个,那么我建议不要使用dask.bag,而是使用concurrent.futures interface,特别是as_completed迭代器。

  

C)鉴于这种情况持续很长时间,有时工人或AWS盒子死亡,最好存储进度?

只要你能保证调度程序能够存活,Dask就应该具有弹性。如果您使用并发期货界面而不是dask bag,那么您还可以在客户端流程上跟踪中间结果。