递归锁、信号量、GIL锁、基于多线程的socket通信和进程池线程池

递归锁、信号量、GIL锁、基于多线程的socket通信和进程池线程池

递归锁

死锁现象:是指两个或两个以上的进程和线程因抢夺计算机资源而产生的一种互相等待的现象

from threading import Thread
from threading import Lock
import time
lock_A = Lock()
lock_B = Lock()
class MyThread(Thread):def run(self):self.f1()self.f2()def f1(self):lock_A.acquire()print(f"{self.name}拿到了A锁")lock_B.acquire()print(f"{self.name}拿到了B锁")lock_B.release()lock_A.release()def f2(self):lock_B.acquire()print(f"{self.name}拿到了B锁")time.sleep(0.1)lock_A.acquire()print(f"{self.name}拿到了A锁")lock_A.release()lock_B.release()
if __name__ == '__main__':for i in range(3):t = MyThread()t.start()
# 结果:
Thread-1拿到了A锁
Thread-1拿到了B锁
Thread-1拿到了B锁
Thread-2拿到了A锁

递归锁:

递归锁有一个计数的功能, 原数字为0,上一次锁,计数+1,释放一次锁,计数-1,

只要递归锁上面的数字不为零,其他线程就不能抢锁.

from threading import Thread
from threading import RLock
import time
lock_A = lock_B = RLock()
class MyThread(Thread):def run(self):self.f1()self.f2()def f1(self):lock_A.acquire()print(f"{self.name}拿到了A锁")lock_B.acquire()print(f"{self.name}拿到了B锁")lock_B.release()lock_A.release()def f2(self):lock_B.acquire()print(f"{self.name}拿到了B锁")time.sleep(0.1)lock_A.acquire()print(f"{self.name}拿到了A锁")lock_A.release()lock_B.release()
if __name__ == '__main__':for i in range(3):t = MyThread()t.start()

信号量

也是一种锁, 控制并发数量

from threading import Thread,Semaphore,current_thread
import time
import random
sem = Semaphore(5)
def task():sem.acquire()print(f"{current_thread().name}厕所ing")time.sleep(random.randint(1,3))print(f"{current_thread().name}厕所ed")sem.release()
if __name__ == '__main__':for i in range(20):t = Thread(target=task,)t.start()

GIL锁

GIL锁的定义:

全局解释锁,就是一把互斥锁,将并发变成串行,同一时刻只能有一个线程使用解释器资源,牺牲效率,保证解释器的数据安全。

py文件在内存中的执行过程:

  • 当执行py文件时,会在内存中开启一个进程
  • 进程中不光包括py文件还有python解释器,py文件中的线程会将代码交给解释器,
  • 解释器将python代码转化为C语言能识别的字节码,然后再交给解释器中的虚拟机将字节码转化为二进制码最后交给CPU执行

1729998-20190826210958038-1706557331.png

当线程1先拿到GIL锁时线程2、线程3就只能等待,当线程1在CPU执行遇到阻塞或执行一段时间后,线程1会被挂起,同时GIL锁会被释放,此时线程2或线程3就会拿到锁进入解释器,同样,当在CPU执行遇到阻塞或执行一段时间后被挂起,同时GIL锁会被释放,此时最后一个线程就会进入解释器。

从上面可以看出,当遇到单个进程中含有多个线程时,由于GIL锁的存在,Cpython并不能利用多核进行并行处理,但可以在单核实现并发。

但不同进程之间的多线程是可以利用多核的。

GIL锁的两个作用:

1、保证解释器里面的数据的安全;

2、强行加锁,减轻开发负担

问题:单进程的多线程不能利用多核

如何判断什么情况使用多线程并发与多进程并发

对计算来说,cpu越多越好,但是对于I/O来说,再多的cpu也没用

  当然对运行一个程序来说,随着cpu的增多执行效率肯定会有所提高(不管提高幅度多大,总会有所提高),这是因为一个程序基本上不会是纯计算或者纯I/O,所以应该相对的去看一个程序到底是计算密集型还是I/O密集型,如下:

#分析:
我们有四个任务需要处理,处理方式肯定是要达到并发的效果,解决方案可以是:
方案一:开启四个进程
方案二:一个进程下,开启四个线程#单核情况下,分析结果: 如果四个任务是计算密集型,没有多核来并行计算,方案一徒增了创建进程的开销,方案二胜如果四个任务是I/O密集型,方案一创建进程的开销大,且进程的切换速度远不如线程,方案二胜#多核情况下,分析结果:如果四个任务是计算密集型,多核意味着并行计算,在python中一个进程中同一时刻只有一个线程执行,可以利用多核,方案一胜如果四个任务是I/O密集型,再多的核也解决不了I/O问题,方案二胜#结论:现在的计算机基本上都是多核,python对于计算密集型的任务开多线程的效率并不能带来多大性能上的提升,甚至不如串行(没有大量切换),但是,对于IO密集型的任务效率还是有显著提升的。

总结:多核前提下,如果任务IO密集型,使用多线程并发;如果任务计算密集型,使用多进程并发。

验证Cpython的并发效率

  • 计算密集型: 单个进程的多线程并发 vs 多个进程的并发并行
from threading import Thread
from multiprocessing import Process
import time
import randomif __name__ == '__main__':# 多进程的并发,并行start_time = time.time()l1 = []for i in range(4):p = Process(target=task,)l1.append(p)p.start()for p in l1:p.join()print(f'执行效率:{time.time()- start_time}')  # 2.5342209339141846
from threading import Thread
from multiprocessing import Process
import time
import randomif __name__ == '__main__':
# 多线程的并发start_time = time.time()l1 = []for i in range(4):p = Thread(target=task,)l1.append(p)p.start()for p in l1:p.join()print(f'执行效率:{time.time()- start_time}')  # 5.262923240661621

​ 总结: 计算密集型: 多进程的并发并行效率高.

  • IO密集型: 单个进程的多线程并发 vs 多个进程的并发并行
from threading import Thread
from multiprocessing import Process
import time
import randomdef task():count = 0time.sleep(random.randint(1,3))count += 1if __name__ == '__main__':# 多进程的并发,并行start_time = time.time()l1 = []for i in range(50):p = Process(target=task,)l1.append(p)p.start()for p in l1:p.join()print(f'执行效率:{time.time()- start_time}')  #  7.145753383636475
from threading import Thread
from multiprocessing import Process
import time
import randomdef task():count = 0time.sleep(random.randint(1,3))count += 1if __name__ == '__main__':start_time = time.time()l1 = []for i in range(50):p = Thread(target=task,)l1.append(p)p.start()for p in l1:p.join()print(f'执行效率:{time.time()- start_time}')  # 3.0278055667877197

​ 总结:对于IO密集型: 单个进程的多线程的并发效率高.

基于多线程的socket通信

客户端:

import socketclient = socket.socket()client.connect(('127.0.0.1',8848))while 1:try:to_server_data = input('>>>').strip()client.send(to_server_data.encode('utf-8'))from_server_data = client.recv(1024)print(f'来自服务端的消息: {from_server_data.decode("utf-8")}')except Exception:break
client.close()

服务端:

import socket
from threading import Threaddef communicate(conn,addr):while 1:try:from_client_data = conn.recv(1024)print(f'来自客户端{addr[1]}的消息: {from_client_data.decode("utf-8")}')to_client_data = input('>>>').strip()conn.send(to_client_data.encode('utf-8'))except Exception:breakconn.close()def _accept():server = socket.socket()server.bind(('127.0.0.1', 8848))server.listen(5)while 1:conn, addr = server.accept()t = Thread(target=communicate,args=(conn,addr))t.start()if __name__ == '__main__':_accept()

进程池线程池

线程池: 一个容器,这个容器限制住你开启线程的数量,比如4个,第一次肯定只能并发的处理4个任务,只要有任务完成,线程马上就会接下一个任务.

from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
import os
import time
import random# print(os.cpu_count()) 获取cpu数量
def task(n):print(f'{os.getpid()} 接客')time.sleep(random.randint(1,3))# 开启进程池  (并行(并行+并发))   
if __name__ == '__main__':p = ProcessPoolExecutor()  # 进程池,默认不写,开启数量为cpu数量for i in range(20):p.submit(task,i)# 开启线程池  (并发)t = ThreadPoolExecutor()  # 默认不写, cpu个数*5 线程数# t = ThreadPoolExecutor(100)  # 100个线程for i in range(20):t.submit(task,i)

转载于:https://www.cnblogs.com/lifangzheng/p/11415009.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/247067.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

10 种机器学习算法的要点(附 Python 和 R 代码)

前言 谷歌董事长施密特曾说过:虽然谷歌的无人驾驶汽车和机器人受到了许多媒体关注,但是这家公司真正的未来在于机器学习,一种让计算机更聪明、更个性化的技术。 也许我们生活在人类历史上最关键的时期:从使用大型计算机&#xff0…

阻塞、非阻塞、同步与异步

阻塞、非阻塞、同步与异步 阻塞与非阻塞 进程运行的三种状态:运行、就绪、阻塞 阻塞和非阻塞: ​ 阻塞:程序运行时,遇到了IO,程序挂起,cpu被切走. ​ 非阻塞: 程序没有遇到IO,程序遇到IO但是我通过某种手段,让cpu强行运行我的程序…

8大策略让你对抗机器学习数据集里的不均衡数据

本文转自:http://www.36dsj.com/archives/35137 http://blog.csdn.net/heyongluoyao8/article/details/49408131 英文版本:http://machinelearningmastery.com/tactics-to-combat-imbalanced-classes-in-your-machine-learning-dataset/ 你是不是也经历…

线程queue、事件event及协程

线程queue、事件event及协程 线程queue 多线程抢占资源,让其保持串行的两种方式: ​ 1、互斥锁 ​ 2、队列 线程队列分为以下三种: 1、Queue(先进先出) import queueq queue.Queue(3) q.put(1) q.put(2) q.put(3) # q…

不平衡数据下的机器学习方法简介

本文转自:http://baogege.info/2015/11/16/learning-from-imbalanced-data/ 引言 不管是在学术界还是工业界,不平衡学习已经吸引了越来越多的关注,不平衡数据的场景也出现在互联网应用的方方面面,如搜索引擎的点击预测&#xff08…

CSS预处理——LESS

LESS是什么? less是一门CSS预处理语言。由于CSS本身并不是程序式语言,不方便维护和扩展,没有变量、函数、作用域等概念。而LESS在CSS的基础语法之上,引入了变量、Mixin混入、运算以及函数等功能,大大简化了CSS的编写&a…

不均衡数据的处理方法

关于不均衡数据的处理方法,主要有以下几个方面: 1. 采样的方法 1.1 过采样,采集类标少的样本,达到平衡样本的目的。 方法一,简单的复制类标少的样本 方法二,生成人工样本(SMOTE方法&#xff09…

.mat,.txt,.csv 数据转换为weka中的arff格式及matlab和Weka之间相互转换格式

在RUSBoost和SMOTEBoost中提供了csv转换为arff格式的方法,详见CSVtoARFF.m http://www.mathworks.com/matlabcentral/fileexchange/37315-rusboost http://cn.mathworks.com/matlabcentral/fileexchange/37311-smoteboost function r CSVtoARFF (data, relation…

IT人不仅要提升挣钱能力,更要拓展挣钱途径

前几天我上班路上,和小区门口开车的师傅闲聊,发现他们虽然学历不高,但挣钱的途径不少,比如固定接送多位客户,然后能通过朋友圈拓展新客户,而且通过客户口口相传,也能不断拉到生意,算…

Class Imbalance Problem

本文转自:http://www.chioka.in/class-imbalance-problem/#comment-202282 What is the Class Imbalance Problem? It is the problem in machine learning where the total number of a class of data (positive) is far less than the total number of another c…

matlab中的类标转换程序

matlab中的类标转换程序 原始类标为Y,新类标为Y_new %进行排序,针对类标数目orig_labels sort(unique(Y)); Y_new Y;new_labels 1:length(orig_labels);for i1:length(orig_labels)Y_new(find(Yorig_labels(i)))Inf;Y_new(isinf(Y_new))new_labels(…

this关键字+super关键字

一.this关键字1.实例一:(1)需求:使用Java类描述一个动物;(2)实例:class Animal{ String name; //成员变量 String color; public Animal(String n,String c){ na…

python中的print

python3 中去除了print语句,加入print()函数实现相同的功能 print() 会在输出窗口中显示一些文本。 >>> print "hello,world!" SyntaxError: Missing parentheses in call to print >>> print("hello,world!") hello,world…

final+static

final final关键字顾名思义代表“最后的”,意味着不能被更改。它的定义,可以概括地分为以下三点: 被final修饰的类不能被继承;被final修饰的方法不能被重写;被final修饰的变量不能被改变。注:引用类型的变量…

程序代码编辑器和浏览器代码编辑器&代码可视化执行过程

tutorialspoint http://www.tutorialspoint.com/codingground.htm 1. Sublime Text :http://blog.l1n3.net/editor/sublime-text-introduce/ 下载 :http://www.sublimetext.com/3 2. Notepad https://notepad-plus-plus.org/zh/ 更多细节请查看 htt…

匿名对象+内部类

匿名对象 普通的类对象在使用时会定义一个类类型的变量,用来保存new出来的类所在的地址。而匿名类取消掉了这个变量,这个地址由编译器来处理,并且在new出来之后,它占用的内存会有JVM自动回收掉。后续无法再使用了。例如 public cl…

听技术播客:一边学Python编程一边学英语

本文转自:http://codingpy.com/article/recommended-python-podcasts/ 学技术的朋友一般都会关注不少技术博客(blog),但是关注技术播客(podcast)的人估计不会太多。这里一方面也是由于相关的播客数量&#…

mysql补充

mysql补充 mysql使用流程 开启服务端,mysqld或者net start mysqlcmd下键入mysql -u root -p,输入设置好的密码,连接mysql客户端show databases;展示所有的mysql仓库创建一个库:create database CRM;然后sho…

编程书单:十本Python编程语言的入门书籍

本文转自:http://codingpy.com/article/10-python-beginner-books/ 本文与大家分享一些Python编程语言的入门书籍,其中不乏经典。我在这里分享的,大部分是这些书的英文版,如果有中文版的我也加上了。有关书籍的介绍,大…

JavaScript异步

JavaScript异步类型 延迟类型:setTimeout、setInterval、setImmediate监听事件:监听new Image加载状态、监听script加载状态、监听iframe加载状态、Message带有异步功能类型: Promise、ajax、Worker、async/awaitJavaScript常用异步编程 Prom…