当前位置: 主页 > Python语言

python 多线程进度条-python 线程 deamon

发布时间:2023-02-10 09:33   浏览次数:次   作者:佚名

本文为Python翻译团队最新出品的翻译。 原作者Michael Discroll,译者cystone,由编程作者EarlGrey校对。 昨天,编程学院发布了多线程编程教程,一篇文章学习Python多线程编程。

译者简介:Cystone,成都信息工程大学计算机学院学生。 专长:图像处理,机器学习。

多处理模块是在 Python 2.6 中添加的。 它最初由 Jesse Noller 和 Richard Oudkerk 在 PEP 371 中定义。 multiprocessing 模块生成进程的方式与使用 threading 模块生成线程的方式相同。 但是在这里,因为您正在使用多处理,所以您可以绕过全局解释器锁 (GIL) 并充分利用机器的多处理器。

多处理模块还包含一些线程模块没有的 API。 例如,有一个简洁的 Pool 类,可让您并行执行具有多个输入的函数。 我们将在后面的章节中接触 Pool。 我们将从多处理模块的 Process 类开始。

多处理入门

Process 类与线程模块的 Thread 类非常相似。 让我们创建一系列调用相同函数的进程,看看它是如何工作的:

python线程管理_python 线程 deamon_python 多线程进度条

在此示例中,我们导入 Process 并创建一个倍增器函数。 在这个函数中,我们将传入的数字加倍。我们还使用 Python 中的 os 模块来获取当前进程的 ID(或 pid)。 这可以告诉我们哪个进程正在调用该函数。 在代码底部的循环中,我们创建了一系列进程并启动它们。 底部循环调用每个进程的 join() 方法,它告诉 Python 等待进程完成。 如果需要结束一个进程,可以调用它的terminate()方法。

运行此代码时,您将看到类似于以下内容的输出:

5 加倍为 10 进程 ID:10468

10 加倍为 20,进程 ID:10469

15 加倍为 30,进程 ID:10470

20 加倍为 40,进程 ID:10471

25 加倍为 50 进程 ID:10472

有时最好有一个具有人类可读名称的进程。 幸运的是,Process 类支持命名进程。 让我们来看看:

python 线程 deamon_python 多线程进度条_python线程管理

这一次,我们介绍一些别的东西:current_process。 current_process 与Threading 模块中的current_thread 基本相同。 我们使用它来获取调用 doubler 函数的线程的名称。 您可能已经注意到我们的前五个进程没有设置名称。 第六个进程我们将其名称设置为“Test”。 让我们看看我们得到的输出:

通过以下方式将 5 加倍为 10:Process-2

10 加倍到 20 通过:Process-3

15 倍增至 30 通过:Process-4

20 加倍到 40 通过:Process-5

25 倍增至 50 通过:Process-6

通过以下方式将 2 加倍为 4:测试

输出显示多处理模块默认为每个进程名称分配一个数字。 当然,我们设置名称的进程是没有编号的。

Multiprocessing 模块与 Threading 模块一样,也支持“锁”。 您需要做的就是导入 Lock,获取它,执行操作然后释放它。 让我们来看看:

python 多线程进度条_python线程管理_python 线程 deamon

这里我们创建了一个函数,直接打印传入的任何内容。为了防止线程被其他东西打扰,我们使用了一个Lock对象。 此代码将遍历我们列表中的三个项目并为每个项目创建一个进程。 每个进程调用该函数,将一个元素从可迭代对象传递给该函数。 因为我们使用了锁python 多线程进度条,所以后续的流程都会等到锁被释放了再进行。

日志

多进程日志和多线程日志有一点区别。 原因是Python的日志包不支持进程共享锁,所以不同进程的日志可能会混在一起。 让我们尝试在上面的示例中添加一个基本日志。 下面是代码:

python 线程 deamon_python线程管理_python 多线程进度条

最简单的记录方式是将所有日志发送到 stderr。 我们可以通过调用函数 log_to_stderr 来做到这一点。 然后我们调用get_logger函数获取记录器(logger),设置日志级别为INFO。 其余代码与之前相同。 这里说明一下,我并没有使用join()函数。 相反,父线程在退出时显式调用 join()。

当你运行上面的代码时,你会得到这样的输出:

[INFO/Process-1] 子进程调用 self.run()

探戈

[INFO/Process-1] 进程正在关闭

[INFO/Process-1] 进程退出,退出代码为 0

[INFO/Process-2] 子进程调用 self.run()

[INFO/MainProcess] 进程正在关闭

狐步舞

[INFO/Process-2] 进程正在关闭

[INFO/Process-3] 子进程调用 self.run()

[INFO/Process-2] 进程退出,退出代码为 0

10

[INFO/MainProcess] 为进程 Process-3 调用 join()

[INFO/Process-3] 进程正在关闭

[INFO/Process-3] 进程退出,退出代码为 0

[INFO/MainProcess] 为进程 Process-2 调用 join()

现在如果要将日志保存到硬盘中,其实还有一些复杂的事情。 可以参考Python官方的例子。

泳池类

Pool 类用于表示工作进程池。 它具有允许您将任务分配给不同工作进程的方法。 让我们看一下这个简单的例子:

python线程管理_python 线程 deamon_python 多线程进度条

在这里,我们创建了一个 Pool 实例,并告诉它创建三个工作进程。 然后我们使用 map 方法将一个函数和一个可迭代对象映射到每个进程。 最后,我们打印出结果,这里的结果是一个列表:[10, 20, 40]。

我们也可以通过 apply_async 方法获取程序的结果:

python 多线程进度条_python线程管理_python 线程 deamon

这样做可以让我们获得过程的结果,这就是 get 函数所做的。 您可能会注意到我们添加了超时(timeout)设置,这是为了防止我们调用的函数出现意外。 我们不希望它无限期地阻塞。

进程通信

如果想让两个进程进行通信,multiprocessing模块提供了两个主要的方法:Queues和Pipes。 队列保证线程和进程安全。 在另一篇关于线程的文章中也有Queue的实现,我们在此基础上做一些修改:

python 线程 deamon_python线程管理_python 多线程进度条

我们需要导入 Queue 和 Process。 然后我们创建两个函数,一个创建数据并将它们放入队列,另一个获取数据并处理它们。 Queue的put()方法用于向队列中添加数据,get()方法用于获取数据。 最后一段代码创建一个队列对象和一些进程python 多线程进度条,并运行它们。 请注意,我们在进程对象上调用了 join() 方法,而不是在 Queue 本身上。

结论

这篇文章讲了很多。 您已经学习了如何对函数使用多处理、使用队列在进程之间进行通信、为线程命名等等。 Python官方文档中还有很多内容本文没有涉及,大家也可以深入研究一下。 但现在您已经了解了如何使用 Python 来利用计算机的全部处理能力。