【发布时间】:2017-05-02 21:08:06
【问题描述】:
我有一个工作项目。我们编写了一个模块,并在那里作为#TODO 来实现线程以改进模块。我是一个相当新的 python 程序员,并决定尝试一下。在学习和实现线程时,我遇到了类似于How many threads is too many? 的问题,因为我们有一个大约需要处理 6 个对象的队列,那么为什么要创建 6 个线程(或任何线程)来处理列表中的对象还是在处理时间可以忽略不计时排队? (每个对象最多需要大约 2 秒来处理)
所以我做了一个小实验。我想知道使用线程是否有性能提升。请参阅下面的 python 代码:
import threading
import queue
import math
import time
results_total = []
results_calculation = []
results_threads = []
class MyThread(threading.Thread):
def __init__(self, thread_id, q):
threading.Thread.__init__(self)
self.threadID = thread_id
self.q = q
def run(self):
# print("Starting " + self.name)
process_data(self.q)
# print("Exiting " + self.name)
def process_data(q):
while not exitFlag:
queueLock.acquire()
if not workQueue.empty():
potentially_prime = True
data = q.get()
queueLock.release()
# check if the data is a prime number
# print("Testing {0} for primality.".format(data))
for i in range(2, int(math.sqrt(data)+1)):
if data % i == 0:
potentially_prime = False
break
if potentially_prime is True:
prime_numbers.append(data)
else:
queueLock.release()
for j in [1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 40, 50, 75, 100, 150, 250, 500,
750, 1000, 2500, 5000, 10000]:
threads = []
numberList = list(range(1, 10001))
queueLock = threading.Lock()
workQueue = queue.Queue()
numberThreads = j
prime_numbers = list()
exitFlag = 0
start_time_total = time.time()
# Create new threads
for threadID in range(0, numberThreads):
thread = MyThread(threadID, workQueue)
thread.start()
threads.append(thread)
# Fill the queue
queueLock.acquire()
# print("Filling the queue...")
for number in numberList:
workQueue.put(number)
queueLock.release()
# print("Queue filled...")
start_time_calculation = time.time()
# Wait for queue to empty
while not workQueue.empty():
pass
# Notify threads it's time to exit
exitFlag = 1
# Wait for all threads to complete
for t in threads:
t.join()
# print("Exiting Main Thread")
# print(prime_numbers)
end_time = time.time()
results_total.append(
"The test took {0} seconds for {1} threads.".format(
end_time - start_time_total, j)
)
results_calculation.append(
"The calculation took {0} seconds for {1} threads.".format(
end_time - start_time_calculation, j)
)
results_threads.append(
"The thread setup time took {0} seconds for {1} threads.".format(
start_time_calculation - start_time_total, j)
)
for result in results_total:
print(result)
for result in results_calculation:
print(result)
for result in results_threads:
print(result)
这个测试找到 1 到 10000 之间的素数。这个设置几乎是从https://www.tutorialspoint.com/python3/python_multithreading.htm 中获取的,但我不是打印一个简单的字符串,而是让线程找到素数。这实际上不是我的真实世界应用程序,但我目前无法测试我为模块编写的代码。我认为这是衡量附加线程效果的一个很好的测试。我的真实世界应用程序处理与多个串行设备的通信。我进行了 5 次测试并取平均值。以下是图表中的结果:
我关于线程和这个测试的问题如下:
这个测试是否能很好地说明应该如何使用线程?这不是服务器/客户端情况。就效率而言,当您不为客户提供服务或处理添加到队列中的任务/工作时,避免并行处理会更好吗?
如果对 1 的回答是“否,此测试不适合使用线程”。那么什么时候呢?一般来说。
如果对 1 的回答是“是的,在这种情况下可以使用线程。”,为什么添加线程最终会花费更长的时间并很快达到平稳状态?相反,为什么要使用线程,因为它比循环计算要长很多倍。
我注意到随着工作与线程的比率接近 1:1,设置线程所需的时间变得更长。那么,线程仅在您创建一次线程并尽可能长时间保持活动状态以处理排队速度可能快于计算速度的请求时有用吗?
【问题讨论】:
-
这个问题确实应该有一个与主题相关的名称。这个想法是为了帮助将来有同样问题的人提供答案。
标签: python multithreading python-multithreading