我想做一个简单的工作。我有一个由n个元素组成的列表,并且想要将该列表分为两个较小的列表,并使用线程执行简单的计算并将其附加到新列表中。我已经编写了一些测试代码,当我有少量元素(例如3000)时,它似乎可以正常工作。但是,当元素列表较大时(30,000),将删除超过12-20k的任务,并且附加操作将不会通过。
我已经读了很多关于什么构成线程安全和排队的知识。我相信这与此有关,但是即使在尝试使用Lock()之后,我仍然似乎无法获得线程安全的线程。
有人可以指出我正确的方向吗?干杯。
# Seperate thread workload
a_genes = genes[0:count_seperator]
b_genes = genes[count_seperator:genes_count]
class GeneThread (Thread):
def __init__(self, genelist):
Thread.__init__(self)
self.genelist = genelist
def run(self):
for gene in self.genelist:
total_reputation = 0
for local_snp in gene:
user_rsid = rsids[0]
if user_rsid is None:
continue
rep = "B"
# If multiplier is 0, don't waste time calculating
if not rep or rep == "G" or rep == "U":
continue
importance = 1
weighted_reputation = importance * mul[rep]
zygosity = "homozygous_minor"
if rep == "B":
weighted_reputation *= z_mul[zygosity]
# Now we apply the spread amplifier, we raise the score to the power of the spread number
rep_square = pow(spread, weighted_reputation)
total_reputation += rep_square
try:
with lock:
UserGeneReputation.append(total_reputation)
except:
pass
start_time = time.time()
# Create new threads
gene_thread1 = GeneThread(genelist=a_genes)
gene_thread2 = GeneThread(genelist=b_genes)
gene_thread1.daemon, gene_thread2.daemon = True, True
# Start new Threads
gene_thread1.start()
gene_thread2.start()
print(len(UserGeneReputation))
print("--- %s seconds ---" % (time.time() - start_time))
答案 0 :(得分:1)
从广义上讲,线程有两种选择。您可以让他们自主,做他们的工作,然后安静地终止自己。或者,您也可以由其他一些线程来管理它们,这些线程监视它们的生命周期并知道何时完成。您的设计绝对需要第二个选项(获得所需的所有结果时还如何知道?),而您选择了第一个(将其设置为自我终止而不受到监视)。
不要使线程守护进程成为线程。相反,在启动它们之后,请等待两个线程完成。那不是最复杂或最优雅的解决方案,而是每个人都首先学到的解决方案。
此方法的问题在于,它迫使您的代码依赖于如何将工作分配给线程。这可能会导致性能问题,因为每次您想知道何时完成工作都不得不创建和销毁线程时,知道工作已经完成的唯一方法就是等待它。理想情况下,您将线程视为以某种方式完成工作的抽象,而必须等待工作完成的代码将等待工作本身完成(通过与工作本身相关联的某种同步),而不是等待线程完成完成。这样,您可以灵活地确定什么线程可以做什么工作,而不必在每次需要分配工作时都继续创建和销毁线程。
但是每个人都可以学习create / join方法。有时确实是最好的选择。即使使用其他方法,您也可能仍然具有外部创建/连接来首先创建线程,通常,请确保它们干净地完成以有序方式关闭程序。