并发编程-3

目录一览

互斥锁

"""
多个程序同时操作一份数据的时候很容易产生数据错乱!!!
为了避免数据错乱 我们需要使用互斥锁
"""
互斥锁
	将并发变成串行 虽然牺牲了程序的执行效率但是保证了数据安全
如何使用
	from multiprocessing import Process, Lock
	mutex = Lock()
	mutex.acquire()  # 抢锁
	mutex.release()  # 释放锁
强调
	互斥锁只应该出现在多个程序操作数据的地方 其他位置尽量不要加
	ps:以后我们自己处理锁的情况很少 只需要知道锁的功能即可
	
悲观锁:对每次访问数据库的操作都是抱有悲观的态度,认为该操作会对数据库做出修改,所以在访问数据库的时候就加了锁
乐观锁:对每次访问数据库的操作都抱有乐观的态度,只有在做出修改的时候才会上锁

线程理论

进程是资源单位
	进程相当于是车间 进程负责给内部的线程提供相应的资源
线程是执行单位
	线程相当于是车间里面的流水线 线程负责执行真正的功能
    
1.一个进程至少含有一个线程
2.多进程与多线程的区别
	多进程
    	需要申请内存空间 需要拷贝全部代码 资源消耗大
	多线程
    	不需要申请内存空间 也不需要拷贝全部代码 资源消耗小
3.同一个进程下多个线程之间资源共享

创建线程的两种方式

from threading import Thread
from multiprocessing import Process
import time

# def task(name):
#     print(f'{name}正在运行')
#     time.sleep(3)
#     print(f'{name}运行结束')


"""
开设线程不需要完整拷贝代码 所以无论什么系统都不会出现反复操作的情况 
也不需要在启动脚本中执行 但是为了兼容性和统一性 习惯在启动脚本中编写
"""


# t = Thread(target=task, args=('jason',))
# t.start()
# print('主线程')
# if __name__ == '__main__':
#     t = Thread(target=task, args=('jason',))
#     t.start()
#     print('主线程')


class MyThread(Thread):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print(f'{self.name}正在运行')
        time.sleep(3)
        print(f'{self.name}运行结束')


obj = MyThread('jason')
obj.start()
print('主线程')

多线程实现TCP服务端并发

比多进程更加简单方便 消耗的资源更少
ps:课下使用多进程或者多线程对比(任务管理器)

join方法

主线程等到子线程运行结束之后再运行
from threading import Thread
import time

def task():
    print('正在执行')
    time.sleep(3)
    print('运行结束')


t = Thread(target=task)
t.start()
t.join()
print('主线程')

同一个进程下线程间数据共享

from threading import Thread

money = 1000


def func():
    global money
    money = 666


t = Thread(target=func)
t.start()
t.join()  # 确保线程运行完毕 再查找money 结果更具有说服性
print(money)

线程对象相关方法

1.进程号
	同一个进程下开设的多个线程拥有相同的进程号
2.线程名
	from threading import Thread, current_thread
	current_thread().name
 	主:MainThread	子:Thread-N
3.进程下的线程数
	active_count()

守护线程

守护线程伴随着被守护的线程的结束而结束

from threading import Thread
import time

def task():
    print('子线程运行task函数')
    time.sleep(3)
    print('子线程运行task结束')


t = Thread(target=task)
# t.daemon = True
t.start()
# t.daemon = True
print('主线程')
"""
进程下所有的非守护线程结束 主线程(主进程)才能真正结束!!!
"""

GIL全局解释器锁

储备知识
	1.python解释器也是由编程语言写出来的
    	Cpython  用C写出来的
 		Jpython  用Java写出来的
    	Pypython 用python写出来的
ps:最常用的就是Cpython(默认)
# 官方文档对GIL的解释
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

"""
1.GIL的研究是Cpython解释器的特点 不是python语言的特点
2.GIL本质也是一把互斥锁
3.GIL的存在使得同一个进程下的多个线程无法同时执行(关键)
	言外之意:单进程下的多线程无法利用多核优势 效率低!!!
4.GIL的存在主要是因为cpython解释器中垃圾回收机制不是线程安全的
"""
参考群内截图 理解上述3、4解读
1.误解:python的多线程就是垃圾 利用不到多核优势
	python的多线程确实无法使用多核优势 但是在IO密集型的任务下是有用的
2.误解:既然有GIL 那么以后我们写代码都不需要加互斥锁
	不对 GIL只确保解释器层面数据不会错乱(垃圾回收机制)
	针对程序中自己的数据应该自己加锁处理
3.所有的解释型编程语言都没办法做到同一个进程下多个线程同时执行
ps:我们平时在写代码的时候 不需要考虑GIL 只在学习和面试阶段才考虑!!!
posted @ 2022-08-10 21:34  初学者-11  阅读(23)  评论(0编辑  收藏  举报