飞行的猪哼哼

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

一:进程
1:概念:
进程:操作系统进行资源分配的基本单位。

进程知识点总结:

1:导入进程模块
import multiprocess

2:创建子进程
p1 = multiprocess.Process(target=sing)

3:启动子进程
p1.start()

4:获取进程对象
multiprocessing.current_process()

5:获取进程ID
os.getpid()

6:获取父进程ID
os.getppid()

7:杀死进程
os.kill(os.getpid(), 9)

8:进程带有参数

元组传参
p1 = multiprocessing.Process(target=sing, args=(6))

字典传参
注意:kwargs中键必须和参数名相同
p2 = multiprocessing.Process(target=dance, kwargs={"num": 4})

9:设置守护线程

子进程对象名.daemon = True

子进程自杀:
子进程对象名.tarminate()

线程知识点总结:

1:导线程包
import threading

2:创建子线程
t1 = threading.Thread(target=sing)

3:启动子线程
t1.start()

4:获取线程对象
threading.current_thread()

5:线程的传参方式:

t1 = threading.Thread(target=sing, args=(3,))
t2 = threading.Thread(target=sing, kwargs={"num": 3})

6:创建守护线程:
方案一:
t1 = threading.Thread(target=sing,daemon=True)
方案二:
t1.setDaemon(True)

方案三:
t1.daemon = True

7:设置线程同步
t1.join()

8:锁的使用

创建锁:
mutex = threading.Lock()

上锁:
mutex.acquire()

解锁:
mutex.release()

线程和进程对比:

- 关系对比:
  - 线程依附进程,有进程才有线程
  - 一个进程默认有一个线程,也可以有多个线程
- 区别对比:
  - 全局变量:
    - 进程不能共享全局变量
    - 线程可以共享全局变量,出现资源竞争问题,可以通过互斥锁和线程同步解决。
  - 开销上:
    - 创建进程的开销比创建线程的开销大
  - 概念上:
    - 进程是操作系统资源分配的单位
    - 线程是cpu调度的单位
  - 关系上:
    - 线程依附进程存在,不能单独存在
  - 稳定性上
    - 多进程编程比单进程多线程编程稳定性更好
- 优缺点对比:
  - 进程:优点(稳定性,可以使用多核)缺点(开销大)
  - 线程:优点(开销小)缺点(不能使用多核)

2:多进程的使用:
三步走:导入包:import multiprocessing—>创建子进程:multiprocessing.Process(target=sing)—>启动子进程:
sing_process.start()

import multiprocessing
import time


# 跳舞任务
def dance():
    for i in range(5):
        print("跳舞中...")
        time.sleep(0.2)


# 唱歌任务
def sing():
    for i in range(5):
        print("唱歌中...")
        time.sleep(0.2)

if __name__ == '__main__':
    # 创建跳舞的子进程
    # group: 表示进程组,目前只能使用None
    # target: 表示执行的目标任务名(函数名、方法名)
    # name: 进程名称, 默认是Process-1, .....
    dance_process = multiprocessing.Process(target=dance, name="myprocess1")
    sing_process = multiprocessing.Process(target=sing)

    # 启动子进程执行对应的任务
    dance_process.start()
    sing_process.start()

3:获取进程编号和父类进程编号:

# 创建一个子进程,在子进程中查看自己的进程编号,和父亲的编号
import multiprocessing
import time
import os

def test():
    print("我是子进程:", multiprocessing.current_process())
    print("我的进程名是: ", multiprocessing.current_process().name)
    print("我的当前进程编号是: ", os.getpid())
    print("我的父进程的编号是: ", os.getppid())
    for i in range(5):
        print("看我能活几轮...")
        # 杀死我自己,9是杀死指令
        os.kill(os.getpid(), 9)




def main():

    p1 = multiprocessing.Process(target=test)
    p1.start()

    print("我是父进程:", multiprocessing.current_process())
    print("我是父进程,我的进程名是: ", multiprocessing.current_process().name)
    print("我是父进程,我的进程编号是: ", os.getpid())
if __name__ == '__main__':
    main()

4:进程执行带有参数的任务:

import multiprocessing
import time

def sing(num, name):

    for i in range(num):
        print("我叫%s,我要唱我的第%d首歌" % (name, i+1))
        time.sleep(1)


def dance(num, name):
    for i in range(num):
        print("我叫%s,我要跳我的第%d首舞" % (name, i+1))
        time.sleep(1)


def main():

    p1 = multiprocessing.Process(target=sing,args=(3,"小明"))
    p2 = multiprocessing.Process(target=dance,kwargs={"num": 5, "name": "小红"})
    p1.start()
    p2.start()



if __name__ == '__main__':
    main()

5:进程之间不共享全局变量:

# 思路:建立一个空数组,在两个进程中分别修改,看输出的情况
import multiprocessing
import time


def test1():
    for i in range(5):
        g_num.append(i)

    print("我是子进程一,我的g_num: ",g_num)


def test2():
    print("我是子进程二,我的g_num: ",g_num)



g_num = []

def main():
    p1 = multiprocessing.Process(target=test1)
    p2 = multiprocessing.Process(target=test2)

    p1.start()
    time.sleep(1)
    p2.start()
    print("我是主进程,我的g_num是: ", g_num)


if __name__ == '__main__':
    main()

# 运行结果是:
# 我是子进程一,我的g_num:  [0, 1, 2, 3, 4]
# 我是主进程,我的g_num是:  []
# 我是子进程二,我的g_num:  []

6:主进程会等待所有的子进程执行结束再结束

# 思路:让子进程花费比自己多的时间
import multiprocessing
import time

def test():
    for i in range(5):
        print("我是子进程,我正在执行......")
        time.sleep(0.2)


def main():
    p = multiprocessing.Process(target=test)
    p.start()

    time.sleep(0.5)
    print("我是主进程,我要结束啦")
    exit()

if __name__ == '__main__':
    main()

# 运行结果:
# 我是子进程,我正在执行......
# 我是子进程,我正在执行......
# 我是子进程,我正在执行......
# 我是主进程,我要结束啦
# 我是子进程,我正在执行......
# 我是子进程,我正在执行......

7:守护主进程以及子进程的销毁:

# 思路:设置子进程.daemon=True或者 子进程杀死自己

import multiprocessing
import time

def test():
    for i in range(5):
        print("我是子进程,我正在执行......")
        time.sleep(0.2)


def main():
    p = multiprocessing.Process(target=test)
    #将子进程设置成守护主线程
    # p.daemon=True

    p.start()

    time.sleep(0.5)
    print("我是主进程,我要结束啦")

    # 在主进程销毁之前杀死子进程
    p.terminate()
    exit()

if __name__ == '__main__':
    main()
#
# 运行结果:
# 我是子进程,我正在执行......
# 我是子进程,我正在执行......
# 我是子进程,我正在执行......
# 我是主进程,我要结束啦

二:线程:
1:定义:线程是CPU调度的基本单位
2:线程的基本使用:

import threading
import time

# 唱歌任务
def sing():
    # 扩展: 获取当前线程
    # print("sing当前执行的线程为:", threading.current_thread())
    for i in range(3):
        print("正在唱歌...%d" % i)
        time.sleep(1)

# 跳舞任务
def dance():
    # 扩展: 获取当前线程
    # print("dance当前执行的线程为:", threading.current_thread())
    for i in range(3):
        print("正在跳舞...%d" % i)
        time.sleep(1)


if __name__ == '__main__':
    # 扩展: 获取当前线程
    # print("当前执行的线程为:", threading.current_thread())
    # 创建唱歌的线程
    # target: 线程执行的函数名
    sing_thread = threading.Thread(target=sing)

    # 创建跳舞的线程
    dance_thread = threading.Thread(target=dance)

    # 开启线程
    sing_thread.start()
    dance_thread.start()

3:线程执行带有参数的任务:

# 思路,主线程向子线程中传递一些参数,在子线程中使用这些参数
import threading
import time


def dance(num,name):
    for i in range(num):
        print("我是%s,我在跳第%d个舞,欢迎观赏" % (name, i))
        time.sleep(0.2)

def sing(num,name):
    for i in range(num):
        print("我是%s,我在唱第%d个歌,欢迎倾听" % (name,i))
        time.sleep(0.2)

def main():
    t1 = threading.Thread(target=dance, args=(5,"小红"))

    # 注意:这里必须键和参数名字相同
    t2 = threading.Thread(target=sing,kwargs={"num": 3,"name":"小绿"})
    t1.start()
    t2.start()


if __name__ == '__main__':
    main()


# # 运行结果:
# 我是小红,我在跳第0个舞,欢迎观赏
# 我是小绿,我在唱第0个歌,欢迎倾听
# 我是小绿,我在唱第1个歌,欢迎倾听
# 我是小红,我在跳第1个舞,欢迎观赏
# 我是小绿,我在唱第2个歌,欢迎倾听
# 我是小红,我在跳第2个舞,欢迎观赏
# 我是小红,我在跳第3个舞,欢迎观赏
# 我是小红,我在跳第4个舞,欢迎观赏

4:线程之间执行没有顺序

# 思路:创建10个线程,分别打印
import  threading
import  time

def test():
    # 为什么要休眠一秒??
    time.sleep(1)
    print("我是线程:",threading.current_thread().name)



def main():

    # 因为循环创建线程,先初始化,再启动,可能的第一个和第二个初始化之间,第一个已经启动完成了。这就导致会顺序创建线程。
    # 用睡眠堵塞每个进程,让他们几乎同一时间启动。
    for i in range(10):
        t1 = threading.Thread(target=test)
        t1.start()

if __name__ == '__main__':
    main()

5:主线程要等待所有子线程结束再结束

# 让子线程花费比主线程更多的时间,使用exit退出主线程
import threading
import time

def test():
    for i in range(5):
        print("我是子线程.....")
        time.sleep(1)
    print("我是子线程,我死啦")


def main():
    t1 = threading.Thread(target=test)
    t1.start()

    time.sleep(1)
    print("----我是主线程,我马上就死啦")
    exit()
    print("----我绝对死透了,你看不到我")

if __name__ == '__main__':
    main()

# 运行结果:
# 我是子线程.....
# ----我是主线程,我马上就死啦
# 我是子线程.....
# 我是子线程.....
# 我是子线程.....
# 我是子线程.....
# 我是子线程,我死啦

6:守护主线程的三种方式:

import threading
import time

def test():
    print("我是子线程,我要用3s")
    time.sleep(3)
    print("主线程没死,我就让你看到")


def main():

    # 方法一:在创建子线程的参数中加上daemon=True
    # t1 = threading.Thread(target=test, daemon=True)
    t1 = threading.Thread(target=test)

    # 方法二:使用子线程的setDaemo方法
    # t1.setDaemon(True)


    # 方法三:设置子线程的daemon参数=True
    t1.daemon = True

    t1.start()

    time.sleep(1)


if __name__ == '__main__':
    main()

7:线程之间共享全局变量:

# 思路:对于一个数据,一个线程向里面写数据,一个线程读数据,看能不能读到另外一个线程写入后的数据

import  threading

import time

def num_add():
    for i in range(4):
        g_num.append(i)

    print("我是子线程一中的g_num: ",g_num)

def num_read():
    print("我是子线程二中的g_num: ", g_num)




g_num = []

def main():

    t1 = threading.Thread(target=num_add)
    t2 = threading.Thread(target=num_read)

    t1.start()
    # 保证子线程一执行完成

    time.sleep(1)
    t2.start()
    print("我是主线程中的g_num: ", g_num)





if __name__ == '__main__':
    main()

# #运行结果
# 我是子线程一中的g_num:  [0, 1, 2, 3]
# 我是子线程二中的g_num:  [0, 1, 2, 3]
# 我是主线程中的g_num:  [0, 1, 2, 3]

8:线程之间共享全局变量存在的问题:

# 思路:如果一个线程给一个全局变量增加100000次,另一个也进行,最后的结果不会是200000,而是在100000到200000之间。
import  threading
import  time

def num_add1():
    for i in range(1000000):
        global g_num
        g_num += 1

    print("当子线程一只想结束g_num是:", g_num)


def num_add2():
    for i in range(1000000):
        global g_num
        g_num += 1

    print("当子线程二只想结束g_num是:", g_num)


g_num = 0

def main():
    t1 = threading.Thread(target=num_add1)
    t2 = threading.Thread(target=num_add2)

    t1.start()
    t2.start()


if __name__ == '__main__':
    main()

# 运行结果:
# 当子线程一只想结束g_num是: 1280374
# 当子线程二只想结束g_num是: 1589925

9:共享变量的解决方案—同步

# 思路:让一个线程执行完,另一个线程再执行
import  threading
import  time

def num_add1():
    for i in range(1000000):
        global g_num
        g_num += 1

    print("当子线程一只想结束g_num是:", g_num)


def num_add2():
    for i in range(1000000):
        global g_num
        g_num += 1

    print("当子线程二只想结束g_num是:", g_num)


g_num = 0

def main():
    t1 = threading.Thread(target=num_add1)
    t2 = threading.Thread(target=num_add2)

    t1.start()
    # 让子线程一执行结束再开启子线程二
    t1.join()
    t2.start()


if __name__ == '__main__':
    main()
#
# 运行结果:
# 当子线程一只想结束g_num是: 1000000
# 当子线程二只想结束g_num是: 2000000

10:共享变量的解决方案—互斥锁

# 思路:让可能出现资源竞争的地方所上锁
import  threading

# 1:创建锁
lock = threading.Lock()


def num_add1():

    # 2:出现资源竞争的地方所上锁
    lock.acquire()
    for i in range(1000000):
        global g_num
        g_num += 1

    print("当子线程一只想结束g_num是:", g_num)
    # 3:执行完释放锁
    lock.release()



def num_add2():

    # 相同地方上锁
    lock.acquire()
    for i in range(1000000):
        global g_num
        g_num += 1

    print("当子线程二只想结束g_num是:", g_num)
    # 相同地方解锁
    lock.release()

g_num = 0

def main():
    t1 = threading.Thread(target=num_add1)
    t2 = threading.Thread(target=num_add2)

    t1.start()
    t2.start()


if __name__ == '__main__':
    main()
#
# 运行结果:
# 当子线程一只想结束g_num是: 1000000
# 当子线程二只想结束g_num是: 2000000


# 问题:为啥不在g_num += 1的前后上锁,而是在循环前后上锁,因为频繁开锁和解锁会降低代码执行效率
# 导致程序运行缓慢

11:死锁:一直等待对方释放锁的情景就是死锁

import threading


lock = threading.Lock()

def get_value(index):

    lock.acquire()


    if index >= len(g_num):
        print("数组下标越界啦")
        lock.release()
        return

    value = g_num[index]
    print(value)
    lock.release()

g_num = [1,2,3]
def main():
    for i in range(30):

        t1 = threading.Thread(target=get_value, args=(i,))
        t1.start()


if __name__ == "__main__":
    main()
posted on 2020-08-06 20:14  飞行的猪哼哼  阅读(33)  评论(0)    收藏  举报