Python中的进程与线程

前言

之前文章给大家介绍了网络编程相关内容和进程如何使用,感兴趣的小伙伴可以前往《这是一篇散文》查看。书接上回,今天给大家介绍一下线程,顺便给进程、线程做一个小结。

一、线程

1.1 概述

线程指的是进程的执行路径, 本身是一个执行单元,也是CPU调度的基本单位。

多线程具有如下特点:

1.多线程的执行具有随机性(无序性), 其实就是在抢CPU的过程, 谁抢到, 谁执行。
2. 默认情况下主线程会等待子线程执行结束再结束。
3. 线程之间会共享当前进程的资源。
4. 多线程环境并发操作共享资源, 有可能引发安全问题, 需要通过线程同步(加锁) 的思想来解决。

1.2 如何使用

格式如下:

1. 导包.   
	import threading
2. 创建线程对象.
	t1 = threading.Thread(target=目标函数)
3. 启动线程.
	t1.start()

示例代码如下:

# 需求:多线程模拟边写代码边听音乐

# 导包
import threading, time

# 创建写代码函数
def coding(name, num):
    for i in range(1, num + 1):
        print(f'{name}正在敲第{i}行代码......')
        time.sleep(0.2)


# 创建听音乐函数
def music(name, count):
    for i in range(1, count + 1):
        print(f'{name}正在听第{i}首音乐-------------')
        time.sleep(0.1)


if __name__ == '__main__':
    # 创建线程对象 传参
    t1 = threading.Thread(name='coding线程', target=coding, args=('文柏', 10))
    t2 = threading.Thread(name='music线程', target=music, kwargs={'count': 11, 'name': '文柏'})
    # 启动线程
    t1.start()
    t2.start()

1.3 守护线程

默认情况下主线程会等待子线程执行结束再结束,实际开发中往往需要主线程结束后,子线程也随之结束,而不是继续执行。那如何实现呢?就是将子线程设置成守护进程。简单理解为“臣随君亡”,子线程就是“殉葬的臣”。

# 导包
import threading,time

# 编写写代码函数
def coding():
    for i in range(10):
        print(f'coding...{i}')
        time.sleep(0.3)


if __name__ == '__main__':
    # 创建线程对象并设置为守护线程
    th = threading.Thread(target=coding,daemon=True)
    # 启动线程
    th.start()
    # 设置主线程(main) 执行1秒后关闭
    time.sleep(1)
    # 打印提示
    print('主线程(main)执行结束了!')

1.4 互斥锁

多线程环境并发操作共享资源, 或者说操作同一个变量时可能出现数据结果存在偏差,结果并非你想要的。这就是引发了安全问题。需要通过线程同步(加锁) 的思想来解决。

格式如下:

创建锁:mutex = threading.Lock()
加锁:mutex.acquire()
解锁:mutex.release()

代码如下:

# 需求:两个线程对全局变量做累加操作

# 导包
import threading,time

# 定义全局变量
global_num = 0

# 创建互斥锁
mutex = threading.Lock()

# 定义函数1 对global_num累加100次
def fun1():
    #加锁
    mutex.acquire()
    # 声明全局变量 避免警告
    global global_num
    for i in range(100):
        # 具体的累加动作
        global_num +=1
    # 解锁
    mutex.release()  # 如果故意不解锁 可以模拟死锁的情况
    # 打印累加结果
    print(f'fun1计算结果是{global_num}')

# 定义函数2对全局变量累加
def fun2():
    # 加锁
    mutex.acquire()
    # 声明全局变量
    global global_num
    for i in  range(100):
        global_num += 1
    # 解锁
    mutex.release()
    # 累加后打印结果
    print(f'fun2计算结果为{global_num}')

if __name__ == '__main__':
    # 创建线程对象
    f1 = threading.Thread(target=fun1)
    f2 = threading.Thread(target=fun2)

    # 启动线程
    f1.start()
    f2.start()
    

    
  # 通过添加互斥锁就可以保证两个函数在处理数据时相对有序,避免发生安全问题。看官可以测试一下如果不解锁,不在适当位置加锁,使用两个不同的互斥锁会发生什么情况?

二、进程与线程的区别

2.1关系区别

​ 线程是依赖进程的, 且1个进程至少会有1个线程。

2.2 特点区别

​ 1.进程间数据是相互隔离的, 线程间数据是可以共享的。
​ 2.线程间同时操作共享数据, 可能引发安全问题, 需要用到互斥锁的思路解决。

​ 3.进程的资源开销要比 线程的资源开销大。
​ 4.进程程序比单进程多线程程序要更加的稳定。

2.3 优缺点

​ 进程: 可以实现多核操作, 资源开销较大。
​ 线程: 不能使用多核, 资源开销相对较小。

总结

进程和线程中大部分概念和用法是类似的。简单来说线程是依赖进程的,进程数据隔离, 线程数据共享。进程资源开销比线程资源开销大, 所以相对更稳定。但是无论是多进程程还是多线程, 都可以实现多任务。终极目标都是充分利用CPU资源, 提高程序的执行效率。好了,以上就是本期对进程和线程的介绍。我们下期见。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值