Python-----线程、进程、协程

本文详细介绍了Python中的线程、进程和协程。线程是程序执行的最小单元,主线程用于创建子线程,而子线程在主线程结束后会自动退出。进程是资源分配的最小单位,进程间无法共享全局变量。协程在单线程中通过暂停和恢复实现多任务,适合处理IO密集型任务。GIL全局解释器锁在多线程中限制了Python的并行计算能力,但可以通过多进程或协程来规避这个问题。
摘要由CSDN通过智能技术生成

线程
多任务:操作系统可以同时运行多个任务。
python 默认是单任务
线程: 被称为轻量级进程,是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是CPU调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所拥有的全部资源
主线程:当⼀个程序启动时,就有⼀个进程被操作系统(OS)创建,与此同时⼀个线程也⽴刻运 ⾏,该线程通常叫做程序的主线程
主线程的重要性:
1)是产生其他子线程的线程
2)通常它必须最后完成执行各种关闭动作
子线程:可以看做是程序执⾏的⼀条分⽀,当⼦线程启动后会和主线程⼀起同时执⾏
使用threading .Thread(target=函数名,args=(参数列表,元组))创建子线程对象

import time
import threading


def sing():
    for i in range(5):
        print("正在唱歌 .....")
        time.sleep(0.5)


def dance():
    for i in range(5):
        print("正在跳舞 .....")
        time.sleep(0.5)


if __name__ == '__main__':
    # 如果不使用线程,只能5次唱歌后才能进行5次跳舞,不能同时唱歌跳舞,而且速度慢
    # sing()
    # dance()

    # 使用threading .Thread(target=函数名,args=(参数列表,元组))创建子线程对象
    # 线程  传递参数有 三种方式
    # 1.元组 threading.thread(target = 函数名,args=(参数1,参数2,......))元组中元素的顺序和函数的参数顺序一致
    # 2.字典 threading.thread(target = 函数名,kwargs={“参数名”:"参数值",.....})
    # 3.混合元组和字典 threading.thread(target = 函数名,args=(参数1,参数2,......),kwargs={“参数名”:"参数值",.....})
    sing_thread = threading.Thread(target=sing)
    dance_thread = threading.Thread(target=dance)
    # 线程对象.start()启动子线程(子线程同时执行,这样就可以同时唱歌跳舞,但是多线程程序的执⾏顺序是不确定的)
    sing_thread.start()
    dance_thread.start()
    # 使用多线程并发的操作,花费时间要短很多

除了使用threading.Thread创建线程,也可以通过自定义一个类继承threading.Thread类,并且重写run()方法,然后通过实例化自定义对象.start()方法启动自定义线程。调⽤start() ⽅法,但是对象的run⽅法被执⾏了,说明 start⽅法中调⽤了 run⽅法。其中的__init__方法需要调用父类的init方法,super().init()
查看线程数量:
threading.enumerate() 获取当前所有活跃线程的列表。使用len()对列表求长度可以看到当前活跃的线程的个数。
获取当前线程对象:
threading.current_thread() 获取当前线程对象(含名称)
守护线程:如果在程序中将⼦线程设置为守护线程,则该⼦线程会在主线程结束时⾃动退出,设 置⽅式为thread.setDaemon(True),要在thread.start()之前设置。默认是false的,也就是主线程结束 时,⼦线程依然在执⾏。

# 导入时间和线程模块
from time import sleep
import threading

def work1():
    for i in range(10):
        print("正在执行.....", i)
        sleep(0.5)


if __name__ == '__main__':  
    #  创建子线程
    t1 = threading.Thread(target=work1)
    # ****设置子线程为守护线程,如果不设置这个,即使主线程exit,子线程也会继续执行****
    t1.setDaemon(True)
    # 启动子线程
    t1.start()
    sleep(2)
    print("Game Over .....")
    exit()

并发:
指的是任务数多于cpu核数,通过操作系统的各种任务调度算法,实现⽤多个任务“⼀起”执 ⾏(实际上总有⼀些任务不在执⾏,因为切换任务的速度相当快,看上去⼀起执⾏⽽已)
真正的并⾏执⾏多任务只能在多核CPU上实现,但是,由于任务数量远远多 于CPU的核⼼数量, 所以,操作系统也会⾃动把很多任务轮流调度到每个核 ⼼上执⾏。
并行:
指的是任务数⼩于等于cpu核数,即任务真的是⼀起执⾏的
多线程 共享 全局变量数据
产生的问题:
线程对全局变量随意修改可能造成多线程之间对全局变量的混乱(即线程⾮安全)
如果多个线程同时对同一个全局变量操作,会造成资源竞争的问题,导致计算结果有误。
解决方法:
优先让某个线程先执行,使用线程对象.join()方法解决,缺点:把多线程变成了单线程,影响了整体性能
如下:

import threading
from time import sleep
# 定义全局变量
num = 0


def work1():
    global num
    for i in range(1000000):
        num += 1
    print("work1 num = %d" % num) #1000000


def work2():
    global num
    for i in range(1000000):
        num += 1
    print("work2 num= %d" % num) #2000000


if __name__ == '__main__':
    work1_thread = threading.Thread(target=work1)
    work2_thread = threading.Thread(target=work2)
    work1_thread.start()
    # work1执行完后再执行work2
    work1_thread.join()
    work2_thread.start()

    # while 循环的作⽤是:能保证⼦线程运⾏完毕,再去输出 num
    while len(threading.enumerate()) != 1:
        sleep(2)
    print("num = ",num) # 2000000

同步:
在多任务中 多个任务执行有先后顺序,一个执行完毕后,另外一个再执行(这个可以解决线程同时修改全局变量)
异步:
在多任务中 多个任务执行没有先后顺序,多个任务同时执行
线程的锁机制:
当线程获取资源后,立刻进行锁定,资源使用完毕后再解锁,有效的保证同一时间只有一个线程在使用资源
互斥锁:
当多个线程几乎同时修改某一个共享数据的时候,需要进行共同控制。线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。

# 创建锁
mutex= threading.Lock()
# 锁定
mutex.acquire()
# 释放
mutex.release()

死锁:
在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁
进程
进程: 是资源分配的最小单位,也是线程的容器。
程序:程序时固定不变的,而进程会根据运行需要,让操作系统动态分配各种资源(如内存,cpu,磁盘,网络)
进程的状态:
在这里插入图片描述

首先导包,import multiprocessing,使用multiprocessing.Process(target=函数名)创建进程对象,使用.start()方法启动进程,当然除了target这个参数,还可以用args元组方式和kwargs字典方式传参
获取当前进程对象名称:multiprocessing.current_process()
设置名称:multiprocessing.Process(target=xxx,name=“进程名称”)
获取进程号id:multiprocessing.current_process().pid / os.getpid()
获取进程父id:os.getppid()
进程之间 不能共享 全局变量
底层原理:子进程会复制主进程的资源到内部运行
给子进程传递参数方法和给子线程传递参数方法基本一致!
守护进程:p1.daemon=True 设置⼦进程 p1 守护主进程,当主进程结束的时候,⼦进程也随之结束。默认情况下,主进程会等待子进程结束才结束。
p1.terminate() 终⽌进程执⾏,并⾮是守护进程
进程间的通信:
消息队列
创建队列,队列的操作写入和读取,获取队列中消息的个数,判断队列是否为空或者已满==


```python
# 导入模块
import multiprocessing
# 定义消息队列,如果不指定队列长度,则默认为最大,
# 如果指定了消息队列的大小,则消息队列就有上限控制
queue = multiprocessing.Queue(4)
# queue.put()向消息队列中放入任意类型的值
queue.put(1)
queue.put("hello")
queue.put([1, 2, 3])
queue.put({
   "name": "wenmei", "age": 18})
# 当超出队列长度时,进入阻塞状态,直到从消息队列腾出空间为止
#queue.put((1, 2, 3))
# 消息队列如果没有空间可写入,则会立刻抛出"Queue.Full"异常
queue.put_nowait((1, 2, 3))
# 判断队列是否已满
isFull = queue.full()
print("isFull -------->",isFull)

print(queue) # <multiprocessing.queues.Queue object at 0x0000021D09E957F0>

# queue.get 获取第一个值
value1 = queue.get()
print(value1)
# queue.get 获取第二个值
value2 = queue.get()
print(value2)
........
value5 = queue.get_nowait()
print(value5)

# 获取队列中消息的个数
print("消息的个数:",queue.qsize())
# 判断队列是否为空
isEmpty = queue.empty()
print("isEmpty------>", isEmpty)

"""

```python
思路:利用队列在两个进程间进行传递,进而实现数据共享
1.准备两个进程
2.准备一个队列,一个进程向队列写入数据,另一进程从队列读数据
"""
#导入模块
import multiprocessing
from time import sleep
# 写入数据到队列的函数
def wirte_queue(queue):
    for i in range(10):
        # 判断是否已满
        if queue.full():
            print("队列已满!")
            break
        queue.put(i)
        print("写入成功,已经写入:" ,i)
        sleep(0.5)


# 读取队列数据并显示的函数
def read_queue(queue):
    while True:
        if queue.empty():
            print("队列为空!")
            break
        value = queue.get()
        print("已经读取:", value)


if __name__ == '__main__':
    # 创建一个空的队列
    create_queue = multiprocessing.Queue(5)
    # 创建2个进程,分别读写
    wirte_process = multiprocessing.Process(target=wirte_queue,args=(create_queue,))
    read_process = multiprocessing.Process(target=read_queue,args=(create_queue,))
    wirte_process.start()
    # 优先写数据,结束后再读取数据
    wirte_process.join()
    read_process.start()

进程池:当需要创建的⼦进程数量不多时,可以直接利⽤multiprocessing中的Process动态成⽣多个进程,但如果是上百甚⾄上千个⽬标,⼿动的去创建进程的⼯作量巨⼤,此时就可以⽤到multiprocessing模块提 供的Pool⽅法。
同步方式ÿ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值