python 多进程,多线程

代码在没执行时叫做程序。执行中称为进程

多进程实现方式:

  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进程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值