一个程序默认就是一个进程,操作系统通过这个进程来提供内存等资源,一个进程相当于是一个公司,下面执行任务的员工,也就是线程,所以线程就是任务调度的基本单位,一个进程下面默认就是一个线程。
多任务的执行方式有并发执行与并行执行两种,所谓并发就是指在一段时间内交替执行任务,这对应于单核CPU多任务场景;并行指的是同时执行任务,对应于多核CPU多任务场景。
一个程序默认为一个进程,也叫作主进程,利用python的multiProcessing开启多进程后,子进程会将主进程的代码资源全部进行拷贝,然后再执行该进程的任务,这就表明,子进程之间是无法共享数据变量的,因为他们的资源都是从主进程那拷贝过来,然后各自为政。需要注意的是,linux系统下,子进程不会拷贝主进程创建子进程的代码段,但是windows下如果不把进程创建代码放入main函数中,子进程也会拷贝创建子进程的代码,导致的后果就是子进程不断的产生新的子进程。主进程的执行需要等待子进程全部执行完,每个子进程的执行是乱序的,如果想子进程不印象主进程的执行可以通过将子进程设置为守护子进程(sub_process.damen=True)或者直接销毁子进程(sub_process.terminate())的方式。
from multiprocessing import Process
import os
# 列表a在此作为全局变量(列表作为可变类型,数据修改在原始内存上,修改后内存地址不变)
a = list()
def read1():
#os.getpid() 获取当前进程号
#os.getppid() 获取父进程号
print(os.getpid(), os.getppid())
for i in range(4):
a.append(i)
print(a)
def read2():
print(os.getpid(), os.getppid())
for i in range(6,10):
a.append(i)
print(a)
# windows下必须加main模块
if __name__ == '__main__':
#子进程1
read1_process = Process(target=read1)
#子进程2
read2_process = Process(target=read2)
#开始两个子进程, 乱序
read1_process.start()
read2_process.start()
#等待子进程结束后
read1_process.join()
read2_process.join()
#非子进程
read1()
以上代码执行后,通过进程号可以看出各个进程的关系,并且发现a列表字在各个进程中是不共享的,另外一个程序对于同一个进程只能启动一次,否则得创新创建进程。
线程是进程的员工,所以各个线程之间是共享全局变量的,就像他们都在一家公司,公司的资源对于他们都是共同的。一般情况就是一个进程下面一个主线程,主线程开辟几个子线程。同样主线程的执行需要等待子线程执行结束,或者也可以将子线程设置为守护子线程以不影响主线程的执行。
import threading
# a为不可变类型, 每一次修改a的值,都会重新创建a的地址空间
a = 1
def threading1():
global a
a = a + 1
# 输出当前的线程号
print(threading.current_thread())
print('thread1', a)
def threading2():
global a
a = a + 1
print(threading.current_thread())
print('thread1', a)
if __name__ == '__main__':
print(threading.current_thread())
thread1 = threading.Thread(target=threading1)
thread2 = threading.Thread(target=threading2)
thread1.start()
thread2.start()
thread2.join()
thread1.join()
线程之间虽然可以共享全局变量,但实际上及其容易出错,在线程不同步的情况下,容易出现,一个线程正在操作全局变量但还未写回,另一个线程取得还未写回的全局变量。虽然通过上锁(创建锁:thread_lock=threading.lock(),等待锁:thread_lock.require(),释放锁:thread_lock.release(),一个线程抢到锁后开始执行,执行结束后把锁丢出去,如果没有丢出去就变成死锁了,程序GG)或者逐个线程执行的方式完成线程同步,但这样相当于把一个并行任务改成了串行,这样是无意义的,所以一般情况下,我觉得不应该使用多线程进行数据处理并行任务。