Python学习笔记

Posted 刘翾

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python学习笔记相关的知识,希望对你有一定的参考价值。

文章目录

1. 进程

线程是最小的执行单元,而进程由至少一个线程组成
这部分可能会多一些, 写JS写的比较多, 接触进程还是在上学搞java的时候.

1.1. 系统原生 OS 模块, 创建进程

fork函数是UNIX或类UNIX中的分叉函数,fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程


https://baike.baidu.com/item/fork/7143171?fr=aladdin

子进程永远返回0,而父进程返回子进程的ID.

import os

print('Process (%s) start...' % os.getpid())

# Only works on Unix/Linux/Mac:
pid = os.fork()
if pid == 0:
    print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))
else:
    print('I (%s) just created a child process (%s).' % (os.getpid(), pid))

1.2. multiprocessing 模块

1.2.1. Process 单进程

multiprocessing模块就是跨平台版本的多进程模块. multiprocessing模块提供了一个Process类来代表一个进程对象.

from multiprocessing import Process
import os

# 子进程要执行的代码
def run_proc(name):
    print('Run child process %s (%s)...' % (name, os.getpid()))

# if 块只在主进程执行
if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Process(target=run_proc, args=('test',))
    print('Child process will start.')
    p.start()
    p.join()
    print('Child process end.')

=========输出=========
Parent process 27582.
Child process will start.
Run child process test (27584)...
Child process end.

start()方法启动
join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步

1.2.2. Pool 进程池

创建多个进程

from multiprocessing import Pool
import os, time, random

def long_time_task(name):
    print('Run task %s (%s)...' % (name, os.getpid()))
    start = time.time()
    time.sleep(random.random() * 3)
    end = time.time()
    print('Task %s runs %0.2f seconds.' % (name, (end - start)))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Pool(7)
    for i in range(4):
        print('这是主线程的 i: %s' % i)
        p.apply_async(long_time_task, args=(i,))
    print('Waiting for all subprocesses done...')
    p.close()
    p.join()
    print('All subprocesses done.')

=========输出=========

Parent process 27612.
这是主线程的 i: 0
这是主线程的 i: 1
这是主线程的 i: 2
这是主线程的 i: 3
Waiting for all subprocesses done...
Run task 0 (27617)...
Task 0 runs 0.77 seconds.
Run task 1 (27616)...
Task 1 runs 0.92 seconds.
Run task 3 (27614)...
Task 3 runs 1.42 seconds.
Run task 2 (27618)...
Task 2 runs 2.85 seconds.
All subprocesses done.

Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了.

1.3. subprocess 模块 使用外部子进程

subprocess模块可以让我们非常方便地启动一个子进程,然后控制其输入和输出

下面启动一个node看看

import subprocess

print('$ node')
p = subprocess.Popen(['node'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = p.communicate(b'const a = 123\\nconsole.log(11111, a)\\nexit\\n')
print(output.decode('utf-8'))
print('Exit code:', p.returncode)

=========输出=========

$ node
11111 123

2. 线程

多任务可以由多进程完成,也可以由一个进程内的多线程完成. 一个进程至少有一个线程. 线程才是CPU上的执行单元.

2.1. threading 模块, 创建线程

和之前创建进程语法相似, 也是start函数创建, join等待结束

import time, threading

# 新线程执行的代码:
def loop():
    print('thread %s is running...' % threading.current_thread().name)
    n = 0
    while n < 5:
        n = n + 1
        print('thread %s >>> %s' % (threading.current_thread().name, n))
        time.sleep(1)
    print('thread %s ended.' % threading.current_thread().name)

print('thread %s is running...' % threading.current_thread().name)
t = threading.Thread(target=loop, name='LoopThread')
t.start()
t.join()
print('thread %s ended.' % threading.current_thread().name)


=========输出=========


thread MainThread is running...
thread LoopThread is running...
thread LoopThread >>> 1
thread LoopThread >>> 2
thread LoopThread >>> 3
thread LoopThread >>> 4
thread LoopThread >>> 5
thread LoopThread ended.
thread MainThread ended.

主线程实例的名字叫MainThread, 子线程的名字在创建时指定, 也可以不指定. 不指定Python会默认生成一个.

2.2. 锁 LOCK

多线程和多进程最大的不同在于,多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响.
而多线程中,所有变量都由所有线程共享,所以,任何一个变量都可以被任何一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了

我刚刚搜索了下, 其实python有很多种锁, 可是这个网站只介绍了一种, 看来之后还是得找本书看下.

下面是Lock方法的一个例子, acquire获取锁, release释放锁. 一旦一个线程加了锁, 其它线程只能等待, 直到锁被释放,

import threading
# 假定这是你的银行存款:
balance = 0
lock = threading.Lock()
def change_it(n):
    # 先存后取,结果应该为0:
    global balance
    balance = balance + n
    balance = balance - n

def run_thread(n):
    for i in range(1000000):
        change_it(n)

def run_thread_with_lock(n):
    for i in range(100000):
        # 先要获取锁:
        lock.acquire()
        try:
            # 放心地改吧:
            change_it(n)
        finally:
            # 改完了一定要释放锁:
            lock.release()

t1 = threading.Thread(target=run_thread, args=(5,))
t2 = threading.Thread(target=run_thread, args=(8,))
# t1 = threading.Thread(target=run_thread_with_lock, args=(5,))
# t2 = threading.Thread(target=run_thread_with_lock, args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)

=========输出=========

不确定, 但不为0
如果使用这个函数启动线程 run_thread_with_lock 结果正常

2.3. ThreadLocal 模块, 跨函数使用值

ThreadLocal解决了参数在一个线程中各个函数之间互相传递的问题, 每个线程只能读写自己的ThreadLocal变量, 多个线程互不影响.

import threading
    
# 创建全局ThreadLocal对象:
local_school = threading.local()

def process_student():
    # 获取当前线程关联的student:
    std = local_school.student
    print('Hello, %s (in %s)' % (std, threading.current_thread().name))

def process_thread(name):
    # 绑定ThreadLocal的student:
    local_school.student = name
    process_student()

t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()

如果上面代码不用threading的话, 使用全局变量还需要加锁, 或者就是自己手动通过dict模拟.

reference links:

  1. 廖雪峰Python学习文档

以上是关于Python学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

Python学习笔记__14章 virtualenv

python学习笔记——零

Python学习笔记-常用模块

机器学习实战笔记(Python实现)-01-K近邻算法(KNN)

python web 服务器学习笔记

Pipenv 学习笔记