如何生成计数器以查找具有9个前导零的哈希

时间:2019-06-13 19:30:21

标签: python multithreading hash mining

我正在尝试创建一个函数,该函数将使用具有9个前导零的sha1算法生成哈希。哈希是基于一些随机数据的,就像在并发挖掘中一样,我只想向哈希函数中使用的字符串加1。

为了更快,我使用Pool类中的map()使其在我的所有内核上运行,但是如果传递的块大于range(99999999),则会出现问题

return builder.routes()
                .route("rewrite_route", r -> r.path("/**")
                        .filters(f -> f.filter(filter)
                                       .rewritePath("/(?<segment>.*)", "abc//$\\{segment}")
                                       .removeRequestHeader("X-Forwarded-Proto")
                                       .addRequestHeader("authorization","")
                                       .addRequestHeader("apiKey", "qwerwqrw")
                                )
                                        .uri("https://somedomian"))
                .build();
    }

我想创建一个类似于全局计数器的东西,以便在它运行多线程时将其输入到函数中,但是如果我尝试使用range(sys.maxsize),则会收到MemoryError(我知道,因为我没有有足够的RAM,很少有),但是我想将range()生成的列表拆分为多个块。 这有可能还是我应该尝试其他方法?

1 个答案:

答案 0 :(得分:0)

嗨Alin,欢迎来到stackoverflow。

首先,是的,可以使用全局计数器。例如,将multiprocessing.Queuemultiprocessing.Value传递给工作人员。但是,从全局计数器中获取新的数字将导致锁定(并可能等待)计数器。可以而且应该避免这种情况,因为您需要进行大量的计数器查询。我下面提出的解决方案通过安装多个本地计数器来避免全局计数器,这些本地计数器可以像一个全局计数器一样协同工作。

关于代码的RAM消耗,我看到两个问题:

  1. computesha大部分时间返回None值。这将进入由map创建的迭代器中(即使您未分配map的返回值)。这意味着,迭代器比必要的要大得多。
  2. 通常来说,进程完成后,将释放进程的RAM。您的进程开始执行很多任务,所有任务都保留自己的内存。可能的解决方案是maxtasksperchild选项(请参阅multiprocessing.pool.Pool的文档)。当您将此选项设置为1000时,它将在1000个任务后关闭进程并创建一个新任务,以释放内存。

但是,我想提出一种不同的解决方案来解决这两个问题,它对内存非常友好,并且运行速度更快(在我看来,经过N <10次测试后),它是带有maxtasksperchild选项的解决方案:

#!/usr/bin/env python3
import datetime
import multiprocessing
import hashlib
import sys

def computesha(process_number, number_of_processes, max_counter, results):
    counter = process_number # every process starts with a different counter
    data = 'somedata' + 'otherdata'

    while counter < max_counter: #stop after max_counter jobs have been started
        hash = "".join((data,str(counter)))
        newHash = hashlib.sha1(hash.encode()).hexdigest()
        if newHash[:9] == '000000000':
            print(str(newHash))
            print(str(counter))

            # return the results through a queue
            results.put((str(newHash), str(counter)))
        counter += number_of_processes # 'jump' to the next chunk

if __name__ == '__main__':
    # execute this file with two command line arguments:
    number_of_processes = int(sys.argv[1])
    max_counter = int(sys.argv[2])

    # this queue will be used to collect the results after the jobs finished
    results = multiprocessing.Queue()

    processes = []
    # start a number of processes...
    for i in range(number_of_processes):
        p = multiprocessing.Process(target=computesha, args=(i,
                                                             number_of_processes,
                                                             max_counter,
                                                             results))
        p.start()
        processes.append(p)

    # ... then wait for all processes to end
    for p in processes:
        p.join()

    # collect results
    while not results.empty():
        print(results.get())
    results.close()

此代码产生所需的number_of_processes,然后调用computesha函数。如果为number_of_processes=8,则第一个过程为计数器值[0,8,16,24,...]计算哈希,第二个过程为[1,9,17,25]计算依此类推。

此方法的优点:在while循环的每次迭代中,hashnewHash的内存可以重复使用,循环比函数便宜,并且只有number_of_processes个函数调用做出,无趣的结果就被遗忘了。

一个可能的缺点是,计数器是完全独立的,并且每个进程都将完全完成1/number_of_processes,即使某些进程比其他进程更快。最终,该程序与最慢的进程一样快。我没有测量它,但我想这是一个相当理论上的问题。

希望有帮助!