对于单例,多进程的误解

news2024/11/18 1:48:04

单例

  1. 单例在多线程下,可以保证全局唯一,但在多进程下呢?
  2. 子进程不共享父进程的变量

所以,每个进程都维护着一个自己的单例。

验证

创建appserver

flask为例,以包的形式创建一个单例

# view.py--------------------------------------------------------------
from single import indexer
from flask import Blueprint
from flask import jsonify
from flask import request

view_bp = Blueprint("view_bp", __name__)


@view_bp.route("/get")
def get_name():
    print("lock", id(indexer.mu))
    print("indexer", id(indexer))
    return jsonify({"code": 1, "msg": indexer.get()})


@view_bp.route("/set")
def set_name():
    print("lock", id(indexer.mu))
    print("indexer", id(indexer))
    return jsonify({"code": 1, "msg": indexer.set(request.args.get("name"))})


# single.py ----------------------------------------------------------------------
from multiprocessing import Lock


class __Indexer:
    names = set()

    def __init__(self):
        self.mu = Lock()

    def set(self, name):
        self.names.add(name)

    def get(self):
        return self.names.pop()


indexer = __Indexer()


# main.py -----------------------------------------------------------------------
from flask import Flask
from view import view_bp

app = Flask(__name__)
app.register_blueprint(view_bp)

if __name__ == '__main__':
	# 多进程启动
    app.run("0.0.0.0", port=8000, processes=4)

gunicorn去替换flaskwerkzurg(也可以用uwsgi去替换)

# gunicorn.conf

bind = "0.0.0.0:5000"
# 4个worker
workers = 4
backlog = 2048
pidfile = "log/gunicorn.pid"
# accesslog = "log/access.log"
# errorlog = "log/debug.log"
timeout = 600
debug=False
capture_output = True

在这里插入图片描述

假设

如果indexer全局唯一,那么names全局唯一,只要一次set一次get,程序不会报错

实操

set-get一次后程序奔溃,并且可以看到打印出来的内存地址两次不相同

在这里插入图片描述
结论:开启的四个进程,每个进程中都有自己的indexer,并不是唯一。

set替换为Manger().List()

from multiprocessing import Lock
from multiprocessing import Manager


class __Indexer:
    # names = set()
    names = Manager().list()

    def __init__(self):
        self.mu = Lock()

    def set(self, name):
        # self.names.add(name)
        self.names.append(name)

    def get(self):
        return self.names.pop()


indexer = __Indexer()

再次验证,依旧会显示从empty中取值

在这里插入图片描述

使用类方法实现单例(不考虑高并发)

from multiprocessing import Lock
from multiprocessing import Manager


class _Indexer:
    names = set()
    # names = Manager().list()
    instance = None

    @classmethod
    def new(cls):
        if cls.instance is None:
            cls.instance = cls()
            return cls.instance
        else:
            return cls.instance

    def __init__(self):
        self.mu = Lock()

    def set(self, name):
        self.names.add(name)
        # self.names.append(name)

    def get(self):
        return self.names.pop()


# indexer = _Indexer()
indexer = _Indexer.new()

在这里插入图片描述

indexer移出去

# from single import indexer
from single import _Indexer
from flask import Blueprint
from flask import jsonify
from flask import request

view_bp = Blueprint("view_bp", __name__)

indexer = _Indexer.new()

依旧报错,相当于将name随机放到了某个进程下的names当其他进程去取时,自然会报错。
在这里插入图片描述

重新打开Manager()

在这里插入图片描述

结论

到目前为止,可以确定,每一个进程都有自己的indexer

加锁

普通锁

放到single.py

from multiprocessing import Lock
from multiprocessing import Manager

mu = Lock()


class _Indexer:
    names = set()
    # names = Manager().list()
    instance = None

    @classmethod
    def new(cls):
        print("global",mu)
        with mu:
            if cls.instance is None:
                cls.instance = cls()
                return cls.instance
            else:
                return cls.instance

    def __init__(self):
        self.mu = Lock()

    def set(self, name):
        self.names.add(name)
        # self.names.append(name)

    def get(self):
        return self.names.pop()

# indexer = _Indexer()
# indexer = _Indexer.new()

在这里插入图片描述
刚启动,就显示创建了4个锁。。。。

放到main.py

from flask import Flask
from view import view_bp
from multiprocessing import Lock

app = Flask(__name__)
app.register_blueprint(view_bp)

if __name__ == '__main__':
    mu = Lock()
    app.run("0.0.0.0", port=8000, processes=4)

在这里插入图片描述
循环导入,崩溃

Manager().Lock()

from multiprocessing import Lock
from multiprocessing import Manager

# mu = Lock()
mu = Manager().Lock()


class _Indexer:
    names = set()
    # names = Manager().list()
    instance = None

    @classmethod
    def new(cls):
        print(mu)
        with mu:
            if cls.instance is None:
                cls.instance = cls()
                return cls.instance
            else:
                return cls.instance

    def __init__(self):
        self.mu = Lock()

    def set(self, name):
        self.names.add(name)
        # self.names.append(name)

    def get(self):
        return self.names.pop()

# indexer = _Indexer()
# indexer = _Indexer.new()

也是创建了四个锁
在这里插入图片描述
依旧不是全局唯一
在这里插入图片描述

到最后,我自己也乱了,,,,

总之就是,httpserver进程间数据不共享,单例也不是单例,如果要创建单例,应该用fd是否存在去创建,这样所有的进程都可以"看得到这个fd锁"

import os

def lock():
    while True:
        if os.path.exists("./mutex.lock"):
            return False
        else:
            with open("./mutex.lock", "wb") as fd:
                pass
            return True


def unlock():
    os.remove("./mutex.lock")

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

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

相关文章

四十、Java 多线程编程

Java 多线程编程 Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。 多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。 这里定义和…

移动WEB开发之rem布局--苏宁首页案例制作(flexible.js)

简洁高效的rem适配方案flexible.js 手机淘宝团队出的简洁高效 移动端适配库 我们再也不需要在写不同屏幕的媒体查询,因为里面js做了处理 它的原理是把当前设备划分为10等份,但是不同设备下,比例还是一致的。 我们要做的,就是确…

[附源码]Python计算机毕业设计Django学生疫情防控信息填报系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

【Java面试】说说你对ThreadLocal内存泄漏问题的理解

文章目录前置知识为什么会产生内存泄漏问题?如何解决内存泄露问题?为什么要使用弱引用?前置知识 讲解ThreadLocal的内存泄漏问题之前,首先得先知道什么是内存泄漏。 Memory overflow:内存溢出,没有足够的内…

第02章_MySQL环境搭建

目录第02章_MySQL环境搭建服务启动与停止登录MySQL查看版本退出MySQL1. MySQL操作1.1 MySQL的使用演示数据库查看所有的数据库创建数据库使用数据库查看数据库的创建信息删除数据库表格查看数据库的所有表格创建新的表格查看一个表的数据添加一条记录查看表的创建信息删除表格1…

FineReport地图数据图表-按钮控件

1. 概述 1.1 版本 报表服务器版本 功能变更 11.0 -- 1.2 应用场景 「按钮控件」可应用于填报、参数等场景中,添加按钮后,点击按钮可触发某些报表操作。如下图所示: 1.3 如何添加 1.3.1 填报控件 选中单元格后,点击右侧属性…

Python中的__init__.py的高级用法

刚开始学习编程,我们很少会关注这个文件,只知道一个目录中存在该文件,该目录就是一个package,不存在就是普通的目录,普通的目录在导入包时,pycharm并不会智能提示。 Python中每新建一个package都会默认生成…

使用VMware 16 安装中标麒麟 7

目录 1、下载中标麒麟7 2、虚拟机配置 3、NeoKylin7安装 1、下载中标麒麟7 百度网盘:百度网盘 请输入提取码百度网盘为您提供文件的网络备份、同步和分享服务。空间大、速度快、安全稳固,支持教育网加速,支持手机端。注册使用百度网盘即可…

全网最牛最全面的全栈Jmeter性能测试之生成测试报告

结构 ps【文章末尾给大家留下了大量的福利】 测试计划 测试计划是顶级的层级⽬录的结构, 那么在这样的⽬录结构中,⾥⾯可以包含很多线程组 线程组 线程组我们可以简单的理解为postman测试⼯具⾥⾯的collection,那么在整体线程组⾥⾯&…

本地虚拟机linux中nginx搭建

nginx:主要管理服务器中的tomcat,将服务端接受的请求交给nginx来处理,分配给不同的tomcat处理,同时nginx根据每个服务器的性能来配置不同的权重,权重越大访问到的概率就越大,权重越小访问到的概率越低 安装nginx 1,在usr目录下创建…

个人网页设计成品DW静态网页 HTML网页设计结课作业 web课程设计网页规划与设计 Web大学生个人网页成品 web网页设计期末课程大作业

🎉精彩专栏推荐👇🏻👇🏻👇🏻 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业…

QGIS获取行政区geojson数据以及数据乱码修复

安装QGIS 1.下载 访问下面的地址,直接下载安装 https://qgis.org/zh-Hans/site/ 2.设置QGIS语言 点击Settings->Options 点击General,然后按图示选择对应选项。 点击确定,然后等待一会儿,关闭软件重新打开就好了。 安装Qu…

Matplotlib入门[07]——修改默认设置

Matplotlib入门[07]——修改默认设置 参考: https://ailearning.apachecn.org/Matplotlib官网 使用Jupyter进行练习 import numpy as np import matplotlib.pyplot as plt生成三角函数: x np.linspace(-np.pi, np.pi) c, s np.cos(x), np.sin(x)默认绘…

P3 PyTorch 维度变换

前言 参考 课时21 维度变换-2_哔哩哔哩_bilibili 目录: view unsqueeze squeeze Expand repeat 转置 contiguous Permute 例子一 view 作用: 重新调整Tensor的形状,通过shape,或size属性可以看出来 …

Maven从入门到精通

文章目录1.Maven简介1.1 传统项目管理状态分析1.2 什么是maven1.3 Maven的作用2.maven的安装与配置(1)maven的下载与安装(2)Maven目录结构(3)配置settings.xml(4)maven整合idea&…

chapter8——消抖技术

目录1.简介2.开关行为3.开关种类4.消抖5.消抖指南1.简介 在电子设备内两个金属触点随着触点的断开闭合便产生了多个信号,这就是抖动。“消抖”是用以确保在每一次断开或闭合触点时只有一个信号起作用的硬件设备或软件。机械开关和继电器触点通常由弹性金属制造&…

【RobotFramework】FOR循环应用

自动化测试过程中,如果我们想多次运行某段语句,且每次使用的值都不一样,那么我们就要使用到循环。 在Robot FrameWork中,循环使用到的关键字是FOR,常用见应用如下。 应用一: FOR ${变量} IN 参数1 参数2…

知识图谱-KGE-语义匹配-双线性模型-2019:RotatE

【paper】 RotatE: Knowledge Graph Embedding by Relational Rotation in Complex Space【简介】 本文是北大和加拿大的研究团队发表在 ICLR 2019 上的文章,提出了 RotatE(Rotation Embedding),主要思想是将实体表示为复向量&…

Drupal9自定义module添加多个定时任务

drupal的自定义cron常见的就是hook_cron,具体做法参见: Drupal踩坑:在自定义module中添加cron job 这种方法只能一个module添加一个cron。如果想添加多个自定义的cron怎么办?使用hook_cronapi。 有两个模块提供 hook_cronapi&…

DeepLab V3学习笔记

DeepLab V3遇到的问题和解决方法相关工作DeepLab V3中的两种模型结构cascaded modelASPP model相对于DeepLab V2的优化Multi-grid MethodASPP的改进消融实验cascaded model消融实验ASPP model消融实验和其他网络的对比实验总结网络模型图遇到的问题和解决方法 对于DeepLab系列…