首页 > 其他分享 >互斥锁、线程

互斥锁、线程

时间:2022-11-21 20:13:58浏览次数:50  
标签:__ name 互斥 线程 time print import

今日内容概要

  • 多进程实现TCP服务端并发
  • 互斥锁代码实操
  • 线程理论
  • 创建线程的多种方式
  • 线程join方法
  • 守护线程
  • 线程诸多方法
  • GIL全局解释器锁

今日内容详情

多进程实现TCP服务端并发

import socket
from multiprocessing import Process


def get_server():
    server = socket.socket()
    server.bind(('127.0.0.1', 8080))
    server.listen(5)
    return server


def get_talk(sock):
    while True:
        data = sock.recv(1024)
        print(data.decode('utf8'))
        sock.send(data.upper())


if __name__ == '__main__':
    server = get_server()
    while True:
        sock, addr = server.accept()
        p = Process(target=get_talk, args=(sock,))

互斥锁代码实操

锁:建议只加载操作数据的部分 否则整个程序的效率会极低
from multiprocessing import Process, Lock
import time
import json
import random


def search(name):
    with open(r'data.json', 'r', encoding='utf8') as f:
        data = json.load(f)
    print('%s查看票 目前剩余:%s' % (name, data.get('ticket_num')))


def buy(name):
    # 先查询票数
    with open(r'data.json', 'r', encoding='utf8') as f:
        data = json.load(f)
    # 模拟网络延迟
    time.sleep(random.randint(1, 3))
    # 买票
    if data.get('ticket_num') > 0:
        with open(r'data.json', 'w', encoding='utf8') as f:
            data['ticket_num'] -= 1
            json.dump(data, f)
        print('%s 买票成功' % name)
    else:
        print('%s 买票失败 非常可怜 没车回去了!!!' % name)


def run(name, mutex):
    search(name)
    mutex.acquire()  # 抢锁
    buy(name)
    mutex.release()  # 释放锁


if __name__ == '__main__':
    mutex = Lock()  # 产生一把锁
    for i in range(10):
        p = Process(target=run, args=('用户%s号' % i, mutex))
        p.start()
"""
锁有很多种 但是作用都一样
	行锁 表锁 ...
"""

线程理论

进程
	进程其实是资源单位 表示一块内存空间
线程
	线程才是执行单位 表示真正的代码指令

我们可以讲进程比喻是车间 线程是车间里面的流水线
一个进程内部至少含有一个线程

1.一个进程内可以开设多个线程
2.同一个进程下的多个线程数据是共享的
3.创建进程与线程的区别
	创建进程的消耗要远远大于线程

创建线程的两种方式

from threading import Thread
from multiprocessing import Process
import time


def task(name):
    print(f'{name} is running')
    time.sleep(0.1)
    print(f'{name} is over')

if __name__ == '__main__':
    start_time = time.time()
    # p_list = []
    # for i in range(100):
    #     p = Process(target=task, args=('用户%s'%i,))
    #     p.start()
    #     p_list.append(p)
    # for p in p_list:
    #     p.join()
    # print(time.time() - start_time)
    t_list = []
    for i in range(100):
        t = Thread(target=task, args=('用户%s'%i,))
        t.start()
        t_list.append(t)
    for t in t_list:
        t.join()
    print(time.time() - start_time)

t = Thread(target=task, args=('jason',))
t.start()
print('主线程')
"""
创建线程无需考虑反复执行的问题
"""


class MyThread(Thread):
    def run(self):
        print('run is running')
        time.sleep(1)
        print('run is over')

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

线程的诸多特性

1.join方法
2.同进程内多个线程数据共享
3.current_thread()  # 该方法的返回类型是一个Thread类对象,它返回当前处于活动状态的Thread对象。
4.active_count()  # active_count() 是 Python 中线程模块的内置方法。它用于返回任何时刻处于活动状态的 Thread 对象的数量。

GIL全局解释器锁

# 官方文档对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.在CPython解释器中存在全局解释器锁简称GIL
	python解释器有很多类型
		CPython JPython PyPython (常用的是CPython解释器)
2.GIL本质也是一把互斥锁 用来阻止同一个进程内多个线程同时执行(重要)
3.GIL的存在是因为CPython解释器中内存管理不是线程安全的(垃圾回收机制)
	垃圾回收机制
		引用计数、标记清除、分代回收
"""

验证GIL的存在

from threading import Thread

num = 100


def task():
    global num
    num -= 1


t_list = []
for i in range(100):
    t = Thread(target=task)
    t.start()
    t_list.append(t)
for t in t_list:
    t.join()
print(num)

GIL与普通互斥锁

既然CPython解释器中有GIL 那么我们以后写代码是不是就不需要操作锁了!!!
"""
GIL只能够确保同进程内多线程数据不会被垃圾回收机制弄乱 
	并不能确保程序里面的数据是否安全
"""
import time
from threading import Thread,Lock

num = 100


def task(mutex):
    global num
    mutex.acquire()
    count = num
    time.sleep(0.1)
    num = count - 1
    mutex.release()


mutex = Lock()
t_list = []
for i in range(100):
    t = Thread(target=task,args=(mutex,))
    t.start()
    t_list.append(t)
for t in t_list:
    t.join()
print(num)


python多线程是否有用

需要分情况
	情况1
    	单个CPU
		多个CPU
	情况2需要分情况
	情况1
    	单个CPU
    	多个CPU
	情况2
    	IO密集型(代码有IO操作)
       计算密集型(代码没有IO)
 
1.单个CPU
	IO密集型
    	多进程
        申请额外的空间 消耗更多的资源
		多线程
        消耗资源相对较少 通过多道技术
      ps:多线程有优势!!!
 	计算密集型
    	多进程
        申请额外的空间 消耗更多的资源(总耗时+申请空间+拷贝代码+切换)
 		多线程
        消耗资源相对较少 通过多道技术(总耗时+切换)
      ps:多线程有优势!!!
2.多个CPU
	IO密集型
   		多进程
         总耗时(单个进程的耗时+IO+申请空间+拷贝代码)
       多线程
    	  总耗时(单个进程的耗时+IO)
       ps:多线程有优势!!!
	计算密集型
    	多进程
       	  总耗时(单个进程的耗时)
    	多线程
          总耗时(多个进程的综合)
       ps:多进程完胜!!!
 
from threading import Thread
from multiprocessing import Process
import os
import time


def work():
    # 计算密集型
    res = 1
    for i in range(1, 100000):
        res *= i


if __name__ == '__main__':
    # print(os.cpu_count())  # 12  查看当前计算机CPU个数
    start_time = time.time()
    # p_list = []
    # for i in range(12):  # 一次性创建12个进程
    #     p = Process(target=work)
    #     p.start()
    #     p_list.append(p)
    # for p in p_list:  # 确保所有的进程全部运行完毕
    #     p.join()
    t_list = []
    for i in range(12):
        t = Thread(target=work)
        t.start()
        t_list.append(t)
    for t in t_list:
        t.join()
    print('总耗时:%s' % (time.time() - start_time))  # 获取总的耗时

"""
计算密集型
    多进程:5.665567398071289
    多线程:30.233906745910645
"""

def work():
    time.sleep(2)   # 模拟纯IO操作


if __name__ == '__main__':
    start_time = time.time()
    # t_list = []
    # for i in range(100):
    #     t = Thread(target=work)
    #     t.start()
    # for t in t_list:
    #     t.join()
    p_list = []
    for i in range(100):
        p = Process(target=work)
        p.start()
    for p in p_list:
        p.join()
    print('总耗时:%s' % (time.time() - start_time))

"""
IO密集型
    多线程:0.0149583816528320
    多进程:0.6402878761291504
"""
		IO密集型(代码有IO操作)
        计算密集型(代码没有IO)



死锁现象

acquire()  # 抢锁 
release()	# 释放锁

from threading import Thread,Lock
import time

mutexA = Lock()  # 产生一把锁
mutexB = Lock()  # 产生一把锁


class MyThread(Thread):
    def run(self):
        self.func1()
        self.func2()

    def func1(self):
        mutexA.acquire()
        print(f'{self.name}抢到了A锁')
        mutexB.acquire()
        print(f'{self.name}抢到了B锁')
        mutexB.release()
        print(f'{self.name}释放了B锁')
        mutexA.release()
        print(f'{self.name}释放了A锁')

    def func2(self):
        mutexB.acquire()
        print(f'{self.name}抢到了B锁')
        time.sleep(1)
        mutexA.acquire()
        print(f'{self.name}抢到了A锁')
        mutexA.release()
        print(f'{self.name}释放了A锁')
        mutexB.release()
        print(f'{self.name}释放了B锁')

for i in range(10):
    obj = MyThread()
    obj.start()

# 停顿时 第二个线程抢到了第一个进程需要用的锁 第一个进程无法继续执行 进入死锁状态

信号量

1.在python并发编程中信号量相当于多把互斥锁(公共厕所)
2.在有些知识中信号量意思是达到某个条件自动触发其他操作

from threading import Thread, Lock, Semaphore
import time
import random


sp = Semaphore(5)  # 一次性产生五把锁


class MyThread(Thread):
    def run(self):
        sp.acquire()
        print(self.name)
        time.sleep(random.randint(1, 3))
        sp.release()


for i in range(20):
    t = MyThread()
    t.start()

event事件

from threading import Thread, Event
import time

event = Event()  # 类似于造了一个红绿灯


def light():
    print('红灯亮着的 所有人都不能动')
    time.sleep(3)
    print('绿灯亮了 油门踩到底 给我冲!!!')
    event.set()


def car(name):
    print('%s正在等红灯' % name)
    event.wait()  # 如果有Event()的情况下 代码遇到了.wait()才会继续执行
    print('%s加油门 飙车了' % name)


t = Thread(target=light)
t.start()
for i in range(20):
    t = Thread(target=car, args=('熊猫PRO%s' % i,))
    t.start()

进程池与线程池

进程和线程能否无限制的创建 不可以
因为硬件的发展赶不上软件 有物理极限 如果我们在编写代码的过程中无限制的创建进程或者线程可能会导致计算机崩溃

池
	降低程序的执行效率 但是保证了计算机硬件的安全
进程池
	提前创建好固定数量的进程供后续程序的调用 超出则等待
线程池
	提前创建好固定数量的线程供后续程序的调用 超出则等待
 
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
import os
import time
import random
from threading import current_thread

# 1.产生含有固定数量线程的线程池
# pool = ThreadPoolExecutor(10)
pool = ProcessPoolExecutor(5)


def task(n):
    print('task is running')
    # time.sleep(random.randint(1, 3))
    # print('task is over', n, current_thread().name)
    # print('task is over', os.getpid())
    return '我是task函数的返回值'


def func(*args, **kwargs):
    print('from func')

if __name__ == '__main__':
    # 2.将任务提交给线程池即可
    for i in range(20):
        # res = pool.submit(task, 123)  # 朝线程池提交任务
        # print(res.result())  # 不能直接获取
        # pool.submit(task, 123).add_done_callback(func)

"""
线程的返回值需要用异步回调机制获取 不能直接接受返回值
如果直接接受返回值会变成同步 异步回调机制由另一个函数接收
"""

协程

"""
进程:资源单位
线程:执行单位
协程:单线程下实现并发(效率极高)
	在代码层面欺骗CPU 让CPU觉得我们的代码里面没有IO操作
	实际上IO操作被我们自己写的代码检测 一旦有 立刻让代码执行别的
	(该技术完全是程序员自己弄出来的 名字也是程序员自己起的)
		核心:自己写代码完成切换+保存状态
"""
import time
from gevent import monkey;
# gevent模块为第三方模块 需要下载

monkey.patch_all()  # 固定编写 用于检测所有的IO操作(猴子补丁)
from gevent import spawn


def func1():
    print('func1 running')
    time.sleep(3)
    print('func1 over')


def func2():
    print('func2 running')
    time.sleep(5)
    print('func2 over')


if __name__ == '__main__':
    start_time = time.time()
    # func1()
    # func2()
    s1 = spawn(func1)  # 检测代码 一旦有IO自动切换(执行没有io的操作 变向的等待io结束)
    s2 = spawn(func2)
    s1.join()
    s2.join()
    print(time.time() - start_time)  # 8.01237154006958   协程 5.015487432479858

协程实现并发

import socket
from gevent import monkey;monkey.patch_all()  # 固定编写 用于检测所有的IO操作(猴子补丁)
from gevent import spawn


def communication(sock):
    while True:
        data = sock.recv(1024)
        print(data.decode('utf8'))
        sock.send(data.upper())


def get_server():
    server = socket.socket()
    server.bind(('127.0.0.1', 8080))
    server.listen(5)
    while True:
        sock, addr = server.accept()  # IO操作
        spawn(communication, sock)

s1 = spawn(get_server)
s1.join()

如何不断的提升程序的运行效率
	多进程下开多线程 多线程下开协程

标签:__,name,互斥,线程,time,print,import
From: https://www.cnblogs.com/DragonY/p/16913031.html

相关文章

  • 并发编程3 线程
    多进程实现TCP服务端并发importsocketfrommultiprocessingimportProcessdefget_server():server=socket.socket()server.bind(('127.0.0.1',8081)......
  • C# 简单实现线程池
    NET6环境开发 实现线程数量,任务队列,非核心线程,及核心线程活跃时间的管理。namespaceCustomThreadPool;///<summary>///线程池类///</summary>publicclassT......
  • 多线程与线程池知识点
    多线程https://www.cnblogs.com/empty-me/p/15664024.htmlJava多线程:向线程传递参数的三种方法......
  • 线程理论
    今日内容详细互斥锁代码实操锁:建议只加载操作数据的部分否则整个程序的效率会很低defsearch(name):withopen(r'joyce.txt','r',encoding='utf8')asf:......
  • 多进程实现TCP服务端并发、互斥锁、线程及代码实现、GIL全局解释器锁、信号量、event
    目录一、多进程实现TCP服务端并发二、互斥锁代码实操1、互斥锁的概念2、互斥锁的使用3、死锁现象4、小结三、线程理论进程线程线程简介为什么要使用多线程?多线程概念多进......
  • C#中多线程的使用(3)async/awaite
    一、简介在这最后一部分,记录一下async/awaite这一组关键字的用法,async/await这一组关键字是在.netframework4.5开始才有的,async是用来修饰方法,await用于方法内部等待......
  • 线程
    线程线程理论进程进程其实是资源单位,表示的是一块内存空间线程线程是执行单位,表示真正的代码指令一个进程内部至少含有一个线程1.一个进程内可以开设多个......
  • 线程和进程和锁
    目录今日内容概要今日内容详细多进程实现TCP服务端并发互斥锁代码实操线程理论创建线程的两种方式线程的诸多特性GIL全局解释器锁验证GIL的存在GIL与普通互斥锁python多线......
  • 多线程、GIL全局解释器锁、协程
    目录多进程实现TCP服务端并发互斥锁代码实操线程理论创建线程的两种方式线程的诸多特性GIL全局解释器锁验证GIL的存在GIL与普通互斥锁python多线程是否有用死锁现象信号量e......
  • 线程理论及threading模块
    线程理论及threading模块线程理论线程和进程在使用方式和调度策略上十分的相似,两者的本质区别在于进程:进程是资源单位,表示一块内存空间线程:线程是执行单位,真正的执行......