Python高级编程技巧-线程与进程(进阶讲解)

1.0 互斥锁和死锁

1.1 互斥锁

  1. 当多个线程想要同时修改某一个共享数据时,就需要进行同步控制。
  2. 某个线程要更改共享数据时,先将其锁定,此时资源的状态为"锁定",其他线程不能改变,只到该线程释放资源,将资源的状态变成"非锁定",其他的线程才能再次锁定该资源。
  3. 互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
    如下:
import threading

num = 100
#添加线程demo,并写入两个形参
def demo(count,suo1):
	#把num转为全局变量
    global num
    #锁定
    suo1.acquire()
    for i in range(count):
        num += 1
    #解锁
    suo1.release()
    print(f"demo---{num}")

def demo2(count,suo2):
    global num
    #锁定
    suo2.acquire()
    for i in range(count):
        num += 1
    #解锁
    suo2.release()
    print(f"demo2---{num}")

def main():
    #1.创建互斥锁
    start_s1 = threading.Lock()
    #创建多线程
    t1 = threading.Thread(target=demo,args=(1000000,start_s1))
    t2 = threading.Thread(target=demo2,args=(1000000,start_s1))
    #启动多线程,执行
    t1.start()
    t2.start()
    #守护子进程
    t1.join()
    t2.join()
    print(f"Thread----{num}")
if __name__ == '__main__':
    main()
打印结果:
demo---1000100
demo2---2000100
Thread----2000100

2.0 死锁

在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。

  1. 连续加多把锁,也会造成死锁(用RLOCK解决)
  2. 如下这种方式也会造成死锁
import threading
import time

class MyThread1(threading.Thread):
    def run(self):
        # 对mutexA上锁
        mutexA.acquire()

        # mutexA上锁后,延时1秒,等待另外那个线程 把mutexB上锁
        print(self.name+'----do1---up----')
        time.sleep(1)

        # 此时会堵塞,因为这个mutexB已经被另外的线程抢先上锁了
        mutexB.acquire()
        print(self.name+'----do1---down----')
        mutexB.release()

        # 对mutexA解锁
        mutexA.release()

class MyThread2(threading.Thread):
    def run(self):
        # 对mutexB上锁
        mutexB.acquire()

        # mutexB上锁后,延时1秒,等待另外那个线程 把mutexA上锁
        print(self.name+'----do2---up----')
        time.sleep(1)

        # 此时会堵塞,因为这个mutexA已经被另外的线程抢先上锁了
        mutexA.acquire()
        print(self.name+'----do2---down----')
        mutexA.release()

        # 对mutexB解锁
        mutexB.release()

mutexA = threading.Lock()
mutexB = threading.Lock()

if __name__ == '__main__':
    t1 = MyThread1()
    t2 = MyThread2()
    t1.start()
    t2.start()

避免死锁
• 程序设计时要尽量避免
• 添加超时时间等

3.0 线程同步

我们使用 threading.Condition() 完成线程同步。
使用方式如下:
cond = threading.Condition()
等待
cond.wait()
唤醒
cond.notify()

例一实现:
天猫精灵:小爱同学
小爱同学:在
天猫精灵:现在几点了?
小爱同学:你猜猜现在几点了

import threading
from threading import Condition
class TianMao(threading.Thread):
    def __init__(self,mutex,cond):
        super().__init__(name="天猫精灵")
        self.mutex = mutex
        self.cond = cond
    def run(self):
        # self.mutex.acquire()
        # print(f"{self.name}:小爱同学")
        # self.mutex.release()
        #
        # self.mutex.acquire()
        # print(f"{self.name}:现在几点了?")
        # self.mutex.release()
        with self.cond:
            print(f"{self.name}:小爱同学")
            #1先等待
            cond.wait()
            cond.notify()
            print(f"{self.name}:现在几点了?")


class XiAi(threading.Thread):
    def __init__(self,mutex,cond):
        super().__init__(name="小爱同学")
        self.mutex = mutex
        self.cond = cond
    def run(self):
        # self.mutex.acquire()
        # print(f"{self.name}:在")
        # self.mutex.release()
        #
        # self.mutex.acquire()
        # print(f"{self.name}:你猜猜现在几点了?")
        # self.mutex.release()
        with self.cond:
            cond.notify()
            print(f"{self.name}:在")
            cond.wait()
            print(f"{self.name}:你猜猜现在几点了?")

if __name__ == '__main__':
    mutex = threading.RLock()
    cond = threading.Condition()
    t1 = TianMao(mutex,cond)
    t2 = XiAi(mutex,cond)
    t1.start()
    t2.start()
输出的结果:
天猫精灵:小爱同学
小爱同学:在
天猫精灵:现在几点了?
小爱同学:你猜猜现在几点了?

4.0 多任务版UDP聊天

• 创建套接字
• 绑定本地信息
• 获取对方IP和端口
• 发送、接收
• 创建两个线程,去执行功能


import threading
import socket

'''
• 创建套接字
• 绑定本地信息
• 获取对方IP和端口
• 发送、接收
• 创建两个线程,去执行功能
'''
def jie(udp_s):
    while True:
        recv_data = udp_s.recvfrom(1024)
        print(recv_data)

def fa(udp_s,start_ip,start_prot):
    while True:
        send_data = input("请输入需要发送的数据:")
        udp_s.sendto(send_data.encode("gbk"),(start_ip,start_prot))

def main():
    #创建套接字
    udp_s = socket.socket(family=socket.AF_INET,type=socket.SOCK_DGRAM)
    #绑定本地接口
    udp_s.bind(("192.168.1.2", 7080))
    #获取对方的IP端口
    start_ip = input("请输入对方的ip:")
    start_prot = int(input("请输入对方的端口号:"))

    # jie(udp_s)
    # fa(udp_s,start_ip,start_prot)

    start_s1 = threading.Thread(target=jie,args=(udp_s,))
    start_s2 = threading.Thread(target=fa, args=(udp_s,start_ip,start_prot))

    start_s1.start()
    start_s2.start()

if __name__ == '__main__':
    main()

5.0 进程

进程定义:

  1. 进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。
  2. 是操作系统结构的基础。并且进程是线程的容器。
  3. 程序是指令、数据及其组织形式的描述,进程是程序的实体。

进程概念:
• 进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。
• 进程是一个“执行中的程序”。
• 进程是操作系统中最基本、重要的概念。

进程与程序区别:
• 进程:正在执行的程序。动态的,暂时的
• 程序:没有执行的代码,是一个静态的,永久的

Python实现多进程
通过 multiprocessing.Process模块
• group:参数未使用,默认值为None。
• target:表示调用对象,即子进程要执行的任务。
• args:表示调用的位置参数元祖。
• kwargs:表示调用对象的字典。
• name:子进程名称

import multiprocessing
import time
def demo1():
    for i in range(3):
        print("demo1")
        time.sleep(1)
def demo2():
    for i in range(3):
        print("demo2")
        time.sleep(1)
def main():
    t1 = multiprocessing.Process(target=demo1)
    t2 = multiprocessing.Process(target=demo2)

    t1.start()
    t2.start()
if __name__ == '__main__':
    main()

通过继承Process类创建进程

import multiprocessing #创建进程的模块
import time

class A(multiprocessing.Process):
    def run(self):
        for i in range(5):
            print("---1---")
            time.sleep(1)
class B(multiprocessing.Process):
    def run(self):
        for i in range(5):
            print("---2---")
            time.sleep(1)
if __name__ == '__main__':
    t1 = A()
    t2 = B()

    t1.daemon:True   #守护主进程,进程中使用的是daemon的
    # t1.daemon:True
    t1.start()
    t2.start()
    # t1.join()
    # t2.join()
    print("主程序")

进程与线程区别:
• 根本区别
• 进程:操作系统资源分配的基本单位
• 线程:任务调度和执行的基本单位
• 开销
• 进程:通过复制代码+资源创建子进程 每个进程都有独立的代码和数据空间,程序之间的切换会有较大的开销
• 线程:在同一份代码里 创建线程 共享内存 开销较小
• 分配内存
• 进程:系统在运行的时候为每个进程分配不同的内存空间
• 线程:线程所使用的资源是它所属的进程的资源
• 包含关系
• 进程:一个进程可以拥有多个线程
• 线程:线程是进程的一部分

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值