为什么线程会增加处理时间?
Why threading increase processing time?
我正在处理基本的二维 DLA 模拟的多任务处理。扩散有限聚合 (DLA) 是当您让粒子执行随机游走并在接触当前聚合时聚合。
在模拟中,我有 10.000 个粒子在每一步随机走向一个方向。我使用一个工人池和一个队列来喂养他们。我给它们提供了一个粒子列表,工作人员对每个粒子执行方法 .updatePositionAndggregate()
。
如果我有一个工人,我给它提供一个包含 10.000 个粒子的列表,如果我有两个工人,我给他们每个提供一个包含 5.000 个粒子的列表,如果我有 3 个工人,我给他们提供一个列表每个 3.333 个粒子,等等
我现在给你看一些工人的代码
class Worker(Thread):
"""
The worker class is here to process a list of particles and try to aggregate
them.
"""
def __init__(self, name, particles):
"""
Initialize the worker and its events.
"""
Thread.__init__(self, name = name)
self.daemon = True
self.particles = particles
self.start()
def run(self):
"""
The worker is started just after its creation and wait to be feed with a
list of particles in order to process them.
"""
while True:
particles = self.particles.get()
# print self.name + ': wake up with ' + str(len(self.particles)) + ' particles' + '\n'
# Processing the particles that has been feed.
for particle in particles:
particle.updatePositionAndAggregate()
self.particles.task_done()
# print self.name + ': is done' + '\n'
并且在主线程中:
# Create the workers.
workerQueue = Queue(num_threads)
for i in range(0, num_threads):
Worker("worker_" + str(i), workerQueue)
# We run the simulation until all the particle has been created
while some_condition():
# Feed all the workers.
startWorker = datetime.datetime.now()
for i in range(0, num_threads):
j = i * len(particles) / num_threads
k = (i + 1) * len(particles) / num_threads
# Feeding the worker thread.
# print "main: feeding " + worker.name + ' ' + str(len(worker.particles)) + ' particles\n'
workerQueue.put(particles[j:k])
# Wait for all the workers
workerQueue.join()
workerDurations.append((datetime.datetime.now() - startWorker).total_seconds())
print sum(workerDurations) / len(workerDurations)
因此,我打印等待工人终止任务的平均时间。我用不同的线程数做了一些实验。
| num threads | average workers duration (s.) |
|-------------|-------------------------------|
| 1 | 0.147835636364 |
| 2 | 0.228585818182 |
| 3 | 0.258296454545 |
| 10 | 0.294294636364 |
我真的很奇怪为什么添加工人会增加处理时间,我认为至少有 2 个工人会减少处理时间,但它从 .14 秒开始急剧增加。到 0.23 秒。你能解释一下为什么吗?
编辑:
所以,解释是 Python 线程实现,有没有办法让我可以进行真正的多任务处理?
实际创建另一个线程并开始处理它需要时间。由于我们无法控制调度程序,我敢打赌这两个线程都被安排在同一个核心上(因为工作量很小),因此您要增加创建线程所需的时间而不是并行处理完成
发生这种情况是因为 线程不会同时执行 因为 Python 由于 GIL(全局解释器锁),一次只能执行一个线程.
当您生成一个新线程时,除该线程外的所有内容都会冻结。当它停止时,另一个被执行。产生线程需要很多时间。
友好地说,代码根本不重要,因为 任何使用 100 个线程的代码都比 Python 中使用 10 个线程的代码慢(如果更多线程意味着更高的效率和更快的速度,这并不总是正确的)。
这里是 Python docs 的确切引述:
CPython implementation detail:
In CPython, due to the Global Interpreter Lock, only one thread can execute Python code at once (even though certain performance-oriented libraries might overcome this limitation). If you want your application to make better use of the computational resources of multi-core machines, you are advised to use multiprocessing
or concurrent.futures.ProcessPoolExecutor
. However, threading is still an appropriate model if you want to run multiple I/O-bound tasks simultaneously.
Whosebug about GIL
python 中的线程(至少在 2.7 中)由于 GIL 而不会同时执行:https://wiki.python.org/moin/GlobalInterpreterLock - 它们 运行 在单个进程中并共享 CPU,因此您不能使用线程来加快计算速度。
如果您想使用并行计算来加快计算速度(至少在 python2.7 中),请使用进程 - 程序包 multiprocessing
.
这是由于 Python 的全局解释器锁。不幸的是,Python 中的 GIL 线程将阻塞 I/O,因此永远不会超过 1 CPU 核心的使用。看看这里,让您开始了解 GIL:https://wiki.python.org/moin/GlobalInterpreterLock
检查您的 运行 进程(例如 Windows 中的任务管理器),您会注意到您的 Python 应用程序只使用了一个内核。
我建议查看 Python 中的多处理,这不受 GIL 的阻碍:https://docs.python.org/2/library/multiprocessing.html
我正在处理基本的二维 DLA 模拟的多任务处理。扩散有限聚合 (DLA) 是当您让粒子执行随机游走并在接触当前聚合时聚合。
在模拟中,我有 10.000 个粒子在每一步随机走向一个方向。我使用一个工人池和一个队列来喂养他们。我给它们提供了一个粒子列表,工作人员对每个粒子执行方法 .updatePositionAndggregate()
。
如果我有一个工人,我给它提供一个包含 10.000 个粒子的列表,如果我有两个工人,我给他们每个提供一个包含 5.000 个粒子的列表,如果我有 3 个工人,我给他们提供一个列表每个 3.333 个粒子,等等
我现在给你看一些工人的代码
class Worker(Thread):
"""
The worker class is here to process a list of particles and try to aggregate
them.
"""
def __init__(self, name, particles):
"""
Initialize the worker and its events.
"""
Thread.__init__(self, name = name)
self.daemon = True
self.particles = particles
self.start()
def run(self):
"""
The worker is started just after its creation and wait to be feed with a
list of particles in order to process them.
"""
while True:
particles = self.particles.get()
# print self.name + ': wake up with ' + str(len(self.particles)) + ' particles' + '\n'
# Processing the particles that has been feed.
for particle in particles:
particle.updatePositionAndAggregate()
self.particles.task_done()
# print self.name + ': is done' + '\n'
并且在主线程中:
# Create the workers.
workerQueue = Queue(num_threads)
for i in range(0, num_threads):
Worker("worker_" + str(i), workerQueue)
# We run the simulation until all the particle has been created
while some_condition():
# Feed all the workers.
startWorker = datetime.datetime.now()
for i in range(0, num_threads):
j = i * len(particles) / num_threads
k = (i + 1) * len(particles) / num_threads
# Feeding the worker thread.
# print "main: feeding " + worker.name + ' ' + str(len(worker.particles)) + ' particles\n'
workerQueue.put(particles[j:k])
# Wait for all the workers
workerQueue.join()
workerDurations.append((datetime.datetime.now() - startWorker).total_seconds())
print sum(workerDurations) / len(workerDurations)
因此,我打印等待工人终止任务的平均时间。我用不同的线程数做了一些实验。
| num threads | average workers duration (s.) |
|-------------|-------------------------------|
| 1 | 0.147835636364 |
| 2 | 0.228585818182 |
| 3 | 0.258296454545 |
| 10 | 0.294294636364 |
我真的很奇怪为什么添加工人会增加处理时间,我认为至少有 2 个工人会减少处理时间,但它从 .14 秒开始急剧增加。到 0.23 秒。你能解释一下为什么吗?
编辑: 所以,解释是 Python 线程实现,有没有办法让我可以进行真正的多任务处理?
实际创建另一个线程并开始处理它需要时间。由于我们无法控制调度程序,我敢打赌这两个线程都被安排在同一个核心上(因为工作量很小),因此您要增加创建线程所需的时间而不是并行处理完成
发生这种情况是因为 线程不会同时执行 因为 Python 由于 GIL(全局解释器锁),一次只能执行一个线程.
当您生成一个新线程时,除该线程外的所有内容都会冻结。当它停止时,另一个被执行。产生线程需要很多时间。
友好地说,代码根本不重要,因为 任何使用 100 个线程的代码都比 Python 中使用 10 个线程的代码慢(如果更多线程意味着更高的效率和更快的速度,这并不总是正确的)。
这里是 Python docs 的确切引述:
CPython implementation detail:
In CPython, due to the Global Interpreter Lock, only one thread can execute Python code at once (even though certain performance-oriented libraries might overcome this limitation). If you want your application to make better use of the computational resources of multi-core machines, you are advised to use
multiprocessing
orconcurrent.futures.ProcessPoolExecutor
. However, threading is still an appropriate model if you want to run multiple I/O-bound tasks simultaneously.
Whosebug about GIL
python 中的线程(至少在 2.7 中)由于 GIL 而不会同时执行:https://wiki.python.org/moin/GlobalInterpreterLock - 它们 运行 在单个进程中并共享 CPU,因此您不能使用线程来加快计算速度。
如果您想使用并行计算来加快计算速度(至少在 python2.7 中),请使用进程 - 程序包 multiprocessing
.
这是由于 Python 的全局解释器锁。不幸的是,Python 中的 GIL 线程将阻塞 I/O,因此永远不会超过 1 CPU 核心的使用。看看这里,让您开始了解 GIL:https://wiki.python.org/moin/GlobalInterpreterLock
检查您的 运行 进程(例如 Windows 中的任务管理器),您会注意到您的 Python 应用程序只使用了一个内核。
我建议查看 Python 中的多处理,这不受 GIL 的阻碍:https://docs.python.org/2/library/multiprocessing.html