Python之多进程、多线程
一、什么是进程?
区分两个概念程序和进程
程序:计算机程序只不过是磁盘中可执行的二进制等数据。它们只用在被读取到内存中,被操作系统调用时才开始自己的生命周期。
进程(有时被称为重量级进程)是程序的一次执行。每个进程都有自己的地址空间、内存、数据栈以及其它其运行相关的数据。操作系统管理在其上运行的所有进程。进程间都有自己的内存空间、数据栈等,所以只能使用进程间通讯,而不能直接共享信息。
程序与进程的主要区别
1)程序是永存的;进程是暂时的,是程序在数据集上的一次执行,有创建有撤销,存在是暂时的;
2)程序是静态的观念,进程是动态的观念;
进程具有并发性,而程序没有;
进程是竞争计算机资源的基本单位,程序不是。
进程和程序不是一一对应的: 一个程序可对应多个进程即多个进程可执行同一程序; 一个进程可以执行一个或几个程序
二、什么是线程?
线程(有时被称为轻量级进程)跟进程有些相似,不同的是,线程运行在进程中,同一个进程中的线程共享相同的运行环境。
线程与进程的关系
线程有开始,顺序执行和结束三部分。它有一个自己的指令指针,记录自己运行到的地方。线程的运行可以被抢占(中断),或者被暂时挂起(睡眠),让其他线程执行。一个进程中的各个线程之间共享同一片数据空间,所以线程之间可以比进程之间更方便地共享数据和相互通讯。
在多线程并发运行时,如果多个线程共同访问同一片数据,则可能由于数据访问的顺序不一致,有可能导致数据结果不一致。所以线程共享内存是有一定危险性的。
三、什么是Python中的全局解释器锁(GIL)?
Python代码的执行时由Python虚拟机来控制的,其实Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行。虽然Python解释器中可以运行多个线程,但是在任意时刻,只有一个线程在解释器中运行。
对于Python虚拟机的访问由全局解释器锁(Global interpreter lock)来控制,正是由于这个锁能使同一时刻只有一个线程在运行。
四、在Python中使用多进程
注意:每当使用multiprocessing创建新的进程,会复制主进程的所有状态和参数。所以此时调用主进程的全局变量是可以的,但是修改之后不会上传会主进程。
在系统中除了初始化进程,每一个进程都有一个父进程,可能有0个或者多个子进程。由此形成父子进程关系。
在Python中提供了几个用于多进程的模块,今天主要通过Python的multiprocessing模块来创建多进程。
Python多进程示例一:
! -- coding:utf8 --
import multiprocessing
from time import sleep, ctime
def work(flag=0):
print("work %s start!" % flag, ctime())
sleep(4)
print("work %s end!" % flag, ctime())
if name == 'main':
t1 = multiprocessing.Process(target=work, args=(1,))
t2 = multiprocessing.Process(target=work, args=(2,))
t3 = multiprocessing.Process(target=work, args=(3,))
t1.start()
t2.start()
t3.start()
Python多进程示例二:
! -- coding:utf8 --
import multiprocessing
from time import sleep, ctime
def work(flag=0):
print("work %s start!" % flag, ctime())
sleep(4)
print("work %s end!" % flag, ctime())
process_num = 5
def main():
process = []
for i in range(process_num):
t = multiprocessing.Process(target=work, args=(i,))
process.append(t)
for i in process:
i.start()
for i in process:
i.join()
if name == 'main':
main()
Python多进程示例三:
! -- coding:utf8 --
import multiprocessing
from time import sleep, ctime
import os
class MyProcess(multiprocessing.Process):
def __init__(self, flag):
multiprocessing.Process.__init__(self)
self.flag = flag
def run(self):
print("work %s start!" % self.flag, ctime())
print("子进程%s开始执行,pid=%s; 父进程:ppid=%s" % (self.flag, os.getpid(), os.getppid()))
sleep(4)
print("work %s end!" % self.flag, ctime())
process_num = 5
def main():
process = []
for i in range(process_num):
t = MyProcess(i)
process.append(t)
for i in process:
i.start()
for i in process:
i.join()
if name == 'main':
main()
Python多进程之进程池:
为什么要用进程池?
原因 :如果有大量任务需要多进程完成,则可能需要频繁的创建删除进程,给进算计带来较多的资源消耗。
原理 :创建适当的进程放入进程池,用来处理待处理事件,处理完毕后进程不销毁,仍然在进程池中等待处理其他事件。 进程的复用降低了资源的消耗。
Python多进程示例四:
! -- coding:utf8 --
import multiprocessing
from time import sleep, ctime
import os
def work(flag=0):
print("work %s start!" % flag, ctime())
sleep(4)
print("work %s end!" % flag, ctime())
return "work %s success" % flag
def main():
#创建线程池
pool_num = multiprocessing.Pool(4)
process = []
for i in range(10):
p = pool_num.apply_async(func=work, args=(i,))
process.append(p)
#关闭线程池
pool_num.close()
#回收
pool_num.join()
for i in process:
print(i.get())
if name == 'main':
main()
五、在Python中使用多线程
注意:
在Python多线程下,每个线程的执行方式:
获取GIL(Global Interpreter Lock(全局解释器锁))
执行代码直到sleep或者是Python虚拟机将其挂起
释放GIL
在Python中提供了几个用于多线程的模块,包括thread、threading等,thread和threading允许程序员创建和管理线程。
Python多线程示例一:
! -- coding:utf8 --
import threading
from time import sleep, ctime
def work(flag=0):
print("work %s start!" % flag, ctime())
sleep(4)
print("work %s end!" % flag, ctime())
if name == 'main':
t1 = threading.Thread(target=work, args=(1,))
t2 = threading.Thread(target=work, args=(2,))
t3 = threading.Thread(target=work, args=(3,))
t1.start()
t2.start()
t3.start()
Python多线程示例二:
! -- coding:utf8 --
import threading
from time import sleep, ctime
def work(flag=0):
print("work %s start!" % flag, ctime())
sleep(4)
print("work %s end!" % flag, ctime())
thread_num = 5
def main():
threads = []
for i in range(thread_num):
t = threading.Thread(target=work, args=(i,))
threads.append(t)
for i in threads:
i.start()
for i in threads:
i.join()
if name == 'main':
main()
Python多线程示例三:
! -- coding:utf8 --
import threading
from time import sleep, ctime
class MyThread(threading.Thread):
def __init__(self, flag):
threading.Thread.__init__(self)
self.flag = flag
def run(self):
print("work %s start!" % self.flag, ctime())
sleep(4)
print("work %s end!" % self.flag, ctime())
thread_num = 5
def main():
threads = []
for i in range(thread_num):
t = MyThread(i)
threads.append(t)
for i in threads:
i.start()
for i in threads:
i.join()
if name == 'main':
main()
Python多线程之线程同步
如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。使用 Thread 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。
多线程的优势在于可以同时运行多个任务。但是当线程需要共享数据时,可能存在数据不同步的问题。
Python多线程示例四:
! -- coding:utf8 --
import threading
from time import sleep, ctime
sum = 0
class MyThread(threading.Thread):
def __init__(self, flag, my_lock):
threading.Thread.__init__(self)
self.flag = flag
self.my_lock = my_lock
def run(self):
print("work %s start!" % self.flag, ctime())
self.my_lock.acquire()
global sum
for i in range(100000):
sum = sum + 1
self.my_lock.release()
print("work %s end!" % self.flag, ctime())
thread_num = 5
def main():
thread_lock = threading.Lock()
threads = []
for i in range(thread_num):
t = MyThread(i, thread_lock)
threads.append(t)
for i in threads:
i.start()
for i in threads:
i.join()
if name == 'main':
main()
print(sum)