将bruteforce与多线程一起使用时,它比单线程慢

时间:2018-08-26 14:04:22

标签: python multithreading

我想列出从0000zzzz的base36字符串的所有组合。
当我使用单线程运行它时,它的工作速度(〜6-5秒)比多线程(〜13-14秒)要快。
我读过here,为什么使用更多的线程可能比使用更少的线程要慢。
但是我有4个核心(8个逻辑处理器),我认为这不是问题。

我的代码有问题吗?
也许join()函数会减慢速度吗?

这是我的代码:

import time
import threading

# https://codegolf.stackexchange.com/questions/169432/increment-base-36-strings?page=1&tab=votes#tab-top
def inc_base36(s):
   L,R=s[:-1],s[-1:];
   return s and[[L+chr(ord(R)+1),inc_base36(L)+'0'][R>'y'],L+'a'][R=='9']

def bruteforce(start_id, end_id):
 while start_id != end_id:
   start_id = inc_base36(start_id)

# Single thread
# --- 5.15600013733 seconds ---
start_time = time.time()
bruteforce('0000', 'zzzz')
print("--- %s seconds ---" % (time.time() - start_time))

# Two threads
# --- 13.603000164 seconds ---
t1 = threading.Thread(target=bruteforce, args = ('0000', 'hzzz')) # in decimal (0, 839807)
t2 = threading.Thread(target=bruteforce, args = ('i000', 'zzzz')) # in decimal (839808, 1679615)

start_time = time.time()
t1.start()
t2.start()
t1.join()
t2.join()
print("--- %s seconds ---" % (time.time() - start_time))

# Three threads
# --- 14.3159999847 seconds ---
t1 = threading.Thread(target=bruteforce, args = ('0000', 'bzzz')) # in decimal (0, 559871)
t2 = threading.Thread(target=bruteforce, args = ('c000', 'nzzz')) # in decimal (559872, 1119743)
t3 = threading.Thread(target=bruteforce, args = ('o000', 'zzzz')) # in decimal (1119744, 1679615)

start_time = time.time()
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
print("--- %s seconds ---" % (time.time() - start_time))

2 个答案:

答案 0 :(得分:1)

大多数Python实现都有一个GIL(全局解释器锁),该GIL允许一次执行一个线程。您应该使用没有GIL的Jython或在脚本中实现多重处理。

答案 1 :(得分:0)

虽然Yossi的答案是正确的,但更快的解决方案是使用标准库中的工具。

在这种情况下,itertools.product。如果我正确解释了您的问题,则可以执行以下操作:

In [1]: from itertools import product

In [2]: base36 = "0123456789abcdefghijklmnopqrstuvwxyz"

In [3]: res = [''.join(p) for p in product(base36, repeat=4)]

In [4]: res[0], res[-1]
Out[4]: ('0000', 'zzzz')

让我们看看它有多快:

In [5]: %timeit res = [''.join(p) for p in product(base36, repeat=4)]
800 ms ± 1.24 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

如您所见,这要快得多。在旧的core2 CPU上使用CPython 3.6完成了计时。 CPython中的itertools模块是用C语言编写的,这可能是其速度更快的重要原因。

结果似乎是完整的:

In [6]: len(res)
Out[6]: 1679616

In [7]: 36**4
Out[7]: 1679616