Python线程可以在同一进程上工作吗?

2024-05-03 03:22:32 发布

您现在位置:Python中文网/ 问答频道 /正文

我正试图想出一种方法,让线程在同一个目标上工作而不受干扰。在本例中,我使用4个线程将0和90000之间的每个数字相加。此代码运行时几乎立即结束(运行时:0.00399994850159秒),只输出0。最初我想用一个全局变量来实现,但我担心线程之间会相互干扰(即,由于奇怪的读/写时间,两个线程重复计数或跳过一个数字的可能性很小)。所以我提前分配了工作量。如果有更好的方法,请分享。这是我尝试获得多线程经验的简单方法。谢谢

import threading
import time

start_time = time.time()

tot1 = 0
tot2 = 0
tot3 = 0
tot4 = 0

def Func(x,y,tot):
    tot = 0
    i = y-x
    while z in range(0,i):
        tot = tot + i + z

# class Tester(threading.Thread):
#   def run(self):
#       print(n)

w = threading.Thread(target=Func, args=(0,22499,tot1))
x = threading.Thread(target=Func, args=(22500,44999,tot2))
y = threading.Thread(target=Func, args=(45000,67499,tot3))
z = threading.Thread(target=Func, args=(67500,89999,tot4))

w.start()
x.start()
y.start()
z.start()

w.join()
x.join()
y.join()
z.join()

# while (w.isAlive() == False | x.isAlive() == False | y.isAlive() == False | z.isAlive() == False): {}

total = tot1 + tot2 + tot3 + tot4

print total

print("--- %s seconds ---" % (time.time() - start_time))

Tags: 方法falsetargettimeargs线程threadstart
3条回答

你有一个错误,使这个程序几乎立即结束。看看while z in range(0,i):中的Funcz不是在函数中定义的,只有运气好(真的是运气不好),您碰巧有一个全局变量z = threading.Thread(target=Func, args=(67500,89999,tot4))掩盖了问题。您正在测试线程对象是否在整数列表中。。。不是这样的!你知道吗

下一个问题是全局变量。首先,使用一个全局变量不是线程安全的,这是绝对正确的。这些线程会互相干扰。但你误解了全局的工作原理。执行threading.Thread(target=Func, args=(67500,89999,tot4))时,python将当前由tot4引用的对象传递给函数,但函数不知道它来自哪个全局。只更新局部变量tot,并在函数完成时丢弃它。你知道吗

一个解决方案是使用一个全局容器来保存计算,如下面的示例所示。不幸的是,这实际上比仅仅在一个线程中完成所有工作要慢。python全局解释器锁(GIL)一次只允许运行一个线程,并且只会降低纯python实现的CPU密集型任务的速度。你知道吗

您可以查看multiprocessing模块,将其拆分为多个进程。如果运行计算的成本与启动进程并向其传递数据的成本相比是很大的,那么这种方法很有效。你知道吗

以下是您的示例的工作副本:

import threading
import time

start_time = time.time()

tot = [0] * 4

def Func(x,y,tot_index):
    my_total = 0
    i = y-x
    for z in range(0,i):
        my_total = my_total + i + z
    tot[tot_index] = my_total

# class Tester(threading.Thread):
#   def run(self):
#       print(n)

w = threading.Thread(target=Func, args=(0,22499,0))
x = threading.Thread(target=Func, args=(22500,44999,1))
y = threading.Thread(target=Func, args=(45000,67499,2))
z = threading.Thread(target=Func, args=(67500,89999,3))

w.start()
x.start()
y.start()
z.start()

w.join()
x.join()
y.join()
z.join()

# while (w.isAlive() == False | x.isAlive() == False | y.isAlive() == False | z.isAlive() == False): {}

total = sum(tot)


print total

print(" - %s seconds  -" % (time.time() - start_time))

正如其他人所指出的,您可以查看multiprocessing,以便将工作拆分为多个可以并行运行的不同进程。在CPU密集型任务中,如果进程之间没有大量的数据可供传递,这将特别有益。你知道吗

下面是使用^{}对相同功能的简单实现:

from multiprocessing import Pool

POOL_SIZE = 4
NUMBERS = 90000

def func(_range):
    tot = 0
    for z in range(*_range):
        tot += z

    return tot

with Pool(POOL_SIZE) as pool:
    chunk_size = int(NUMBERS / POOL_SIZE)
    chunks = ((i, i + chunk_size) for i in range(0, NUMBERS, chunk_size))
    print(sum(pool.imap(func, chunks)))

在上面的chunks是一个生成器,它生成与原始版本中硬编码的范围相同的范围。它被赋予了^{},其工作原理与标准map相同,只是它在池中的进程中执行函数。你知道吗

关于multiprocessing鲜为人知的事实是,通过使用未记录的multiprocessing.pool.ThreadPool,您可以轻松地将代码转换为使用线程而不是进程。为了将上述示例转换为使用线程,只需将import更改为:

from multiprocessing.pool import ThreadPool as Pool

您可以传入一个可变对象,该对象可以使用标识符添加结果,例如dict或仅使用listappend()添加结果,例如:

import threading

def Func(start, stop, results):
    results.append(sum(range(start, stop+1)))

rngs = [(0, 22499), (22500, 44999), (45000, 67499), (67500, 89999)]
results = []
jobs = [threading.Thread(target=Func, args=(start, stop, results)) for start, stop in rngs]

for j in jobs:
    j.start()

for j in jobs:
    j.join()

print(sum(results))
# 4049955000
# 100 loops, best of 3: 2.35 ms per loop

相关问题 更多 >