代码在没执行时叫做程序。执行中称为进程
多进程实现方式:
1 fork() windows不行,仅支持linux
fork会有个返回值 ,等于0为子进程,大于0为父进程,可以分别去执行下面代码。
import os
import time
ret = os.fork()
if ret==0:
while True:
print("----子进程---")
time.sleep(1)
else:
while True:
print("----父进程---")
time.sleep(1)
2 Process(),将想要子进程执行的代码和需要的参数 传到里面去
from multiprocessing import Process
import time
def test():
while True:
print("---test---")
time.sleep(1)
if __name__ == '__main__':
p = Process(target=test)
p.start() #让这个进程开始执行test函数里的代码
while True:
print("---main---")
time.sleep(1)
运行结果
主进程会等着子进程全部结束才结束。
3 Pool()
from multiprocessing import Pool
import os
import time
def worker(num):
for i in range(5):
print("===pid=%d==num=%d="%(os.getpid(), num))
time.sleep(1)
#3表示 进程池中对多有3个进程一起执行
if __name__ == '__main__':
pool = Pool(3)
for i in range(10):
print("---%d---"%i)
#向进程池中添加任务
#注意:如果添加的任务数量超过了 进程池中进程的个数的话,那么不会导致添加不进入
# 添加到进程中的任务 如果还没有被执行的话,那么此时 他们会等待进程池中的
# 进程完成一个任务之后,会自动的去用刚刚的那个进程 完成当前的新任务
pool.apply_async(worker, (i,))
pool.close()#关闭进程池,相当于 不能够再次添加新任务了
pool.join()#主进程 创建/添加 任务后,主进程 默认不会等待进程池中的任务执行完后才结束
#而是 当主进程的任务做完之后 立马结束,,,如果这个地方没join,会导致
#进程池中的任务不会执行
结果
主进程不会等着子进程结束才结束。不添加join来阻塞主进程的话 ,程序就直接结束了。
如果将apply_async改成apply ,变为堵塞模式,主程序会卡在这,等待上一个程序执行完,在添加新任务。 失去多任务特性。几乎不用。
多线程
使用线程的两种方式
1 使用Thread类
from threading import Thread
import time
#1. 如果多个线程执行的都是同一个函数的话,各自之间不会有影响,各是个的
def test():
print("----haha---")
time.sleep(1)
for i in range(5):
t = Thread(target=test)
t.start()
#传递多个参数 通过元组 嵌列表
t = Thread(target=test1, args=([1,10000],))
t.start()
t2 = Thread(target=test1, args=([10000,20000],))
t2.start()
t3 = Thread(target=test1, args=([20000,30000],))
t3.start()
2 继承Thread类,重写run方法
import threading
import time
class MyThread(threading.Thread):
def run(self):
for i in range(3):
time.sleep(1)
msg = "I'm "+self.name+' @ '+str(i) #name属性中保存的是当前线程的名字
print(msg)
if __name__ == '__main__':
t = MyThread()
t.start()
多线程都修改全局变量,会存在问题,如下面程序
from threading import Thread
import time
g_num = 0
def test1():
global g_num
for i in range(1000000):
g_num += 1
print("---test1---g_num=%d"%g_num)
def test2():
global g_num
for i in range(1000000):
g_num += 1
print("---test2---g_num=%d"%g_num)
p1 = Thread(target=test1)
p1.start()
#time.sleep(3) #取消屏蔽之后 再次运行程序,结果会不一样,,,为啥呢?
# p1.join()
p2 = Thread(target=test2)
p2.start()
print("---g_num=%d---"%g_num)
理论上test2 g_num应该为2000000
原因在于 g_num += 1 为g_num = g_num + 1 刚执行右面的时候 另一个线程开始执行 g_num+ 1,然后回到开始的线程执行g_num = 1, 再回到另一个线程g_num = 1,所以这两个线程计算完g_num应该等于2 却等于1,所以结果会小于2000000
解决方法1:用一个变量flag来确保 一个线程在改变变量的时候不会被另一个变量拿走。 轮询,效率低
解决方法2:使用锁,通知方式
from threading import Thread, Lock
import time
g_num = 0
def test1():
global g_num
#这个线程和test2线程都在抢着 对这个锁 进行上锁,如果有1方成功的上锁,那么导致另外
#一方会堵塞(一直等待)到这个锁被解开为止
for i in range(1000000):
mutex.acquire()
g_num += 1
mutex.release()#用来对mutex指向的这个锁 进行解锁,,,只要开了锁,那么接下来会让所有因为
#这个锁 被上了锁 而堵塞的线程 进行抢着上锁
print("---test1---g_num=%d"%g_num)
def test2():
global g_num
for i in range(1000000):
mutex.acquire()
g_num += 1
mutex.release()
print("---test2---g_num=%d"%g_num)
#创建一把互斥锁,这个锁默认是没有上锁的
mutex = Lock()
p1 = Thread(target=test1)
p1.start()
p2 = Thread(target=test2)
p2.start()
print("---g_num=%d---"%g_num)
异步:会被打断,在做自己的事过程中被叫去做别的,然后再回到自己的任务
from multiprocessing import Pool
import time
import os
def test():
print("---进程池中的进程---pid=%d,ppid=%d--"%(os.getpid(),os.getppid()))
for i in range(3):
print("----%d---"%i)
time.sleep(1)
return "hahah"
def test2(args):
print("---callback func--pid=%d"%os.getpid())
print("---callback func--args=%s"%args)
if __name__ == '__main__':
pool = Pool(3)
pool.apply_async(func=test,callback=test2)
#异步的理解:主进程正在做某件事情,突然 来了一件更需要立刻去做的事情,
#那么这种,在父进程去做某件事情的时候 并不知道是什么时候去做,的模式 就称为异步
while True:
time.sleep(1)
print("----主进程-pid=%d----"%os.getpid())
理论:单核处理器 单线程程序 cpu会跑满,双核处理器,双线程程序 由于gil,每个跑带50%,双核处理器双进程程序 两个核心都跑满
在我自己电脑实验(4核8线程),运行单线程程序,
双进程程序,cpu 最高能跑到 42%
4进程程序, 最高跑到82% (理论是应该跑满吧),一直在浮动,下图没有截到最高的时候,可以看到是开了4个python进程