python(5) subprocess and logging

subprocess

You can use the Python subprocess module to create new processes, connect to their input and output, and retrieve their return codes and/or output of the process.

subprocess run

The subprocess.run() method is a convenient way to run a subprocess and wait for it to complete. Once the subprocess is started, the run() method blocks until the subprocess completes and returns a CompletedProcess object, which contains the return code and output of the subprocess.The check argument is an optional argument of the subprocess.run() function in the Python subprocess module. It is a boolean value that controls whether the function should check the return code of the command being run.When check is set to True, the function will check the return code of the command and raise a CalledProcessError exception if the return code is non-zero. The exception will have the return code, stdout, stderr, and command as attributes.

Note that when there is “&” at the end in command, the run will not wait the process to end. When using eval$command in shell, it’s the same. Don’t use &.

subprocess Popen

subprocess.Popen is a lower-level interface to running subprocesses, while subprocess.run is a higher-level wrapper around Popen that is intended to be more convenient to use. Popen allows you to start a new process and interact with its standard input, output, and error streams. It returns a handle to the running process that can be used to wait for the process to complete, check its return code, or terminate it.
In general, you should use run if you just need to run a command and capture its output and Popen if you need more control over the process, such as interacting with its input and output streams.The Popen class has several methods that allow you to interact with the process, such as communicate(), poll(), wait(), terminate(), and kill().

subprocess call

subprocess.call() is a function in the Python subprocess module that is used to run a command in a separate process and wait for it to complete. It returns the return code of the command, which is zero if the command was successful, and non-zero if it failed.subprocess.call() is useful when you want to run a command and check the return code, but do not need to capture the output.

subprocess check_output

check_output is a function in the subprocess module that is similar to run(), but it only returns the standard output of the command, and raises a CalledProcessError exception if the return code is non-zero.

Subprocess Pipe

A pipe is a unidirectional communication channel that connects one process’s standard output to another’s standard input. A pipe can connect the output of one command to the input of another, allowing the output of the first command to be used as input to the second command.Pipes can be created using the subprocess module with the Popen class by specifying the stdout or stdin argument as subprocess.PIPE.

logging

Logging provides a set of convenience functions for simple logging usage. These are debug(), info(), warning(), error() and critical().
The default level is WARNING, which means that only events of this level and above will be tracked, unless the logging package is configured to do otherwise.

logging config

logging.basicConfig(format=’%(levelname)s %(asctime)s %(process)d %(message)s’, level=logging.DEBUG)
If not printing after config, note that you should config this before importing other libraries incase the config is overriden.

reference

https://www.datacamp.com/tutorial/python-subprocess
https://docs.python.org/3/howto/logging.html

第十八篇 python(4)-多进程

协程、线程与进程

协程、线程和进程是计算机编程中常用的并发编程概念。总的来说,协程适合于高并发、I/O 密集型的场景,可以减少线程切换的开销;线程适合于 CPU 密集型和需要实时响应的任务;而进程则适合于独立性强、资源隔离要求高的任务。在实际应用中,通常会根据任务的特点和需求选择合适的并发编程模型。

协程

协程是一种程序组件,类似于线程,但其执行过程是可中断的。
在协程中,执行可以在特定的位置暂停,并在需要时恢复。
协程通常在单个线程中运行,因此不涉及线程切换的开销,可以有效地利用系统资源。

线程

线程是操作系统能够进行运算调度的最小单位。
一个进程中可以包含多个线程,它们共享进程的内存空间和其他资源。
多线程编程允许程序同时执行多个任务,提高了程序的并发性和响应性。
线程之间的切换开销相对较小,但线程间的共享资源需要进行同步,以避免竞态条件和死锁等问题

进程

进程是程序执行时的一个实例,每个进程都有自己独立的内存空间和系统资源。
进程间相互独立,各自拥有独立的地址空间和资源,彼此之间通信需要特殊的机制。
多进程编程可以充分利用多核处理器,但进程间的切换开销相对较大,因为需要切换地址空间和资源上下文。

python如何使用协程、线程与进程

在Python中,可以使用不同的工具来实现协程、线程和进程。
在Python中,协程通常使用 asyncio 库来实现。 线程可以使用内置的 threading 模块来实现。进程可以使用 multiprocessing 模块来实现。
需要注意的是,在Python中,由于全局解释器锁(GIL)的存在,多线程并不能有效利用多核处理器。因此,如果需要充分利用多核处理器,可以考虑使用多进程。而协程则是在单个线程中实现并发的一种方式,适合于I/O密集型任务。

第十六篇 python(3)-matplotlib绘图

安装

1
2
pip install matplotlib

简单例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import matplotlib.pyplot as plt

# 数据
x = [1, 2, 3, 4, 5]
y = [2, 3, 5, 7, 11]

# 绘图
plt.plot(x, y)

# 添加标题和标签
plt.title('Simple Line Plot')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')

# 显示图形
plt.show()

更多例子

多个子图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import matplotlib.pyplot as plt
import numpy as np

# 数据
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)

# 创建一个包含两个子图的图形
fig, (ax1, ax2) = plt.subplots(2, 1)

# 在第一个子图中绘制正弦函数
ax1.plot(x, y1, 'r-')
ax1.set_title('Sine Function')
ax1.set_xlabel('X-axis')
ax1.set_ylabel('Y-axis')

# 在第二个子图中绘制余弦函数
ax2.plot(x, y2, 'g--')
ax2.set_title('Cosine Function')
ax2.set_xlabel('X-axis')
ax2.set_ylabel('Y-axis')

# 设置图形的整体标题
plt.suptitle('Sine and Cosine Functions')

# 自定义图形的风格
plt.style.use('ggplot')

# 调整子图的间距
plt.tight_layout()

# 显示图形
plt.show()

第十一篇 python(2)-flask+gunicorn+supervisor的python服务部署

过程

部署一个 Python 服务可以通过 Flask 框架、Gunicorn 服务器和 Supervisor 进程管理工具来完成。

1.安装 Flask、Gunicorn 和 Supervisor:

1
pip install flask gunicorn supervisor

  1. 创建一个 Python 脚本,例如 app.py,并添加一个简单的 Flask 应用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from flask import Flask

    app = Flask(__name__)

    @app.route('/')
    def hello():
    return "Hello, World!"

    if __name__ == '__main__':
    app.run()

3.创建 Gunicorn 配置文件:创建一个名为 gunicorn_config.py 的文件,配置 Gunicorn 服务器:

1
2
bind = '0.0.0.0:8000'
workers = 4

4.运行 Gunicorn 服务器:使用 Gunicorn 运行 Flask 应用:

1
gunicorn -c gunicorn_config.py app:app

5.创建 Supervisor 配置文件:创建一个名为 flask_app.conf 的配置文件,配置 Supervisor:

1
2
3
4
5
6
7
[program:flask_app]
directory=/path/to/your/app
command=/path/to/gunicorn -c /path/to/gunicorn_config.py app:app
autostart=true
autorestart=true
stderr_logfile=/var/log/flask_app.err.log
stdout_logfile=/var/log/flask_app.out.log

6.启动 Supervisor:启动 Supervisor 并加载配置文件:

1
sudo supervisord -c /etc/supervisor/supervisord.conf

7.检查应用程序状态:使用 Supervisorctl 命令检查应用程序的状态:

1
sudo supervisorctl status

第九篇 python(1)-语法进阶

yield

yield可以暂停一个函数的运行,返回值给函数调用者,并使得函数可以从上次离开的地方接着运行。通常我们可以借助yield来实现一个生成器。

生成器

生成器是一个可以产生一个序列的函数,调用生成器函数会产生一个生成器对象,并不会开始启动函数,只有当执行__next__()时函数才会执行。生成器时一个一次性操作,和我们常见的列表、字典等可以迭代的对象不同,列表等是可以无限次迭代的。

装饰器

python中函数是一等对象,所以函数可以像普通变量一样当作参数传给另一个函数的,装饰器可以在不改变另一个函数的情况下用来封装另一个函数以拓展这个被封装函数的功能,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。

装饰器不仅可以是函数,也可以是类。使用类装饰器主要依靠类的__call__方法。我们可以直接定义一个装饰器函数或者装饰器类,但是有个缺点是原函数的元信息不见了,比如函数的docstring__name__都会发生改变,此时我们可以使用functools.wrapswraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器里面的函数中。