Python进程及线程编程

简单来讲,进程就是操作系统中运行的程序或任务,进程和程序的区别在于进程是动态的,而程序是静态的。进程是操作系统资源管理的最小单位。

什么是线程:

线程是进程的一个实体,是cpu调度和分派的最小单位,它是比进程更小的能独立运行的基本单位,线程本身不拥有资源,但它可以与同属于一个进程的线程共享进程的资源所拥有的全部资源。

Python多线程编程与GIL:

为了更有效的利用多核处理,就出现了多线程编程,但是问题是线程间数据的一致性和状态的同步如果得到保证,因此python解析器引入了GIL全局锁GIL全局锁的出现虽然保证了线程之间状态和一致性的原则,但是同一时间点上却只能有一个线程在运行。比如:我们有4核CPU,同时发起4个线程,每个线程都在cpu上,但因为GIL全局锁的存在,在同一时间片上只有一个线程,所以多线程并发在python中就是一个美丽的梦。

线程与进程的区别:

1. 线程共享创建它的进程的地址空间;进程有自己的地址空间。
    2. 线程可以直接访问其进程的数据段;进程有自己的父进程数据段的副本。
    3. 新线程很容易创建;新进程需要父进程fork。
    4. 线程可以对同一进程的线程进行相当大的控制;进程只能对子进程执行控制。
    5. 对主线程的更改(取消、优先级变更等)可能会影响进程的其他线程的行为;对父进程的更改不会影响子进程。

python多进程模型

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

1. 进程的基本用法

#!_*_coding:utf-8_*_
# Author: hkey
from multiprocessing import Process    # 导入Process方法
import os

def run_proc():
    print('child process run %s (%s)' %(os.getpid(), os.getppid()))    # os.getpid获取当前进程的pid,os.getppid 获取当前进程的父进程pid


if __name__ == '__main__':
    print('parent process id: ', os.getpid())
    p = Process(target=run_proc)
    p.start()
    p.join()
    print('parent process %s done.' %os.getpid())

创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动。
join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步,当使用join()方法时就阻塞了主进程,直到子进程执行完毕,再次执行主进程

2. 进程池Pool

如果要启动大量子进程,可以用进程池的方式批量创建子进程:

#!_*_coding:utf-8_*_
# Author: hkey
from multiprocessing import Pool, Process
import os, time

def run_proc():
    print('Run task %s (%s)' %(os.getpid(), os.getppid()))
    start_time = time.time()
    time.sleep(1)
    print('Task %s runs %.2f seconds.' %(os.getpid(), time.time()-start_time))

if __name__ == '__main__':
    print('parent process %s' % os.getpid())
    p = Pool(4)
    for i in range(5):
        p.apply_async(run_proc)
    p.close()
    p.join()
    print('parent process %s done.' % os.getpid())


输出结果:

parent process 12980

Run task 8064 (12980)
Run task 9224 (12980)
Run task 11604 (12980)
Run task 13604 (12980)

Task 8064 runs 1.00 seconds.
Run task 8064 (12980)
Task 9224 runs 1.00 seconds.
Task 11604 runs 1.00 seconds.
Task 13604 runs 1.00 seconds.
Task 8064 runs 1.00 seconds.
parent process 12980 done.

上面的例子,进程池最大限制4个子进程,但是循环了5次。从结果可以看到首先建立了4个子进程,当其中一个退出后,再次创建第5个子进程。
特别注意的是,在使用进程池的时候,首先要调用close()方法,调用close()方法后就不能继续添加新的子进程了,然后再调用join()方法。

3. 进程的锁lock

当多个进程需要访问共享资源的时候,Lock可以用来避免访问冲突。
    通过实例测试,在不加锁的情况下,多进程无论在读写同一个文件还是cpu计算都没有发生错误的现象。可能是我测试的量不够。

对文件写入:

#!_*_coding:utf-8_*_
#__author__:"hkey"
import multiprocessing, sys
def write1(f):
    fs = open(f, 'a+')
    n = 10000
    while n > 0:
        fs.write('aaaaaaaaaaaaaa\n')
        n -= 1
    fs.close()

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/065d8208ae91fda8e3f9161255ad5f63.html