为什么Multiprocessing的Lock不会阻止其他进程使用对象?

2023-11-29

以下代码是一家商店的代码,该商店有 5 件商品,三个顾客各需要一件商品。

import multiprocessing as mp
 
class Shop:
    def __init__(self, stock=5):
        self.stock = stock

    def get_item(self, l, x):
        l.acquire()
        if self.stock >= x:
            self.stock -= x
            print(f"{self.stock} = remaining")
        l.release()

if __name__ == "__main__":
    l = mp.Lock()
    obj = Shop()

    p1 = mp.Process(target=obj.get_item, args=(l, 1))
    p2 = mp.Process(target=obj.get_item, args=(l, 1))
    p3 = mp.Process(target=obj.get_item, args=(l, 1))

    p1.start()
    p2.start()
    p3.start()

    p1.join()
    p2.join()
    p3.join()

    print("Final: ", obj.stock)

我得到的输出如下

4 = remaining
4 = remaining
4 = remaining
Final:  5

但是,由于我正在使用Lock我原以为会是这样

4 = remaining
3 = remaining
2 = remaining
Final:  2

问题:如何仅使用锁来实现上述输出(并且没有进程通信,即没有管道/队列)?


此代码未按您预期的方式工作的原因是多处理不与子进程共享其状态。这意味着您启动的每个流程,p1, p2 and p3, 获取类对象的副本Shop。它不是同一个对象。有two解决此问题的方法是共享实例属性stock与进程共享,或共享整个对象本身。如果商店对象保存需要在进程之间共享的其他数据,则第二种方法可能更适合您的较大用例。

Method 1:

只分享价值stock实例变量,您可以使用多处理.值。使用它创建共享整数并访问它们的值的方法如下:

shared_int = multiprocessing.Value('i', 5)
print(f'Value is {shared_int.value}')  # 5 

根据您的用例,代码将变为:

import multiprocessing


class Shop:
    def __init__(self, stock=5):
        self.stock = multiprocessing.Value('i', stock)


    def get_item(self, l, x):
        l.acquire()
        if self.stock.value >= x:
            self.stock.value -= x
            print(f"{self.stock.value} = remaining")
        l.release()


if __name__ == "__main__":
    l = multiprocessing.Lock()
    obj = Shop()

    p1 = multiprocessing.Process(target=obj.get_item, args=(l, 1))
    p2 = multiprocessing.Process(target=obj.get_item, args=(l, 1))
    p3 = multiprocessing.Process(target=obj.get_item, args=(l, 1))

    p1.start()
    p2.start()
    p3.start()

    p1.join()
    p2.join()
    p3.join()

    print("Final: ", obj.stock.value)

Output

4 = remaining
3 = remaining
2 = remaining
Final:  2

Method 2

共享整个复杂对象是一个更复杂的过程。我最近有过answered关于共享复杂对象(例如本例中 Shop 类的对象)的详细类似问题,其中还涵盖了下面提供的代码背后的推理。我建议您阅读它,因为它更详细地解释了底部提供的代码背后的逻辑。此用例的唯一主要区别是您需要使用多进程,多处理的一个分支,而不是多处理。该库的工作方式与内置多处理相同,除了它提供了我们需要的更好的酸洗支持。

基本上,你会想要使用多处理管理器共享状态,以及访问状态的合适代理。这ObjProxy下面的代码中提供了这样一种代理,它共享命名空间以及实例方法(除了受保护/私有属性之外)。一旦你有了这些,你只需要创建类的对象Shop使用管理器和代理。这是使用新添加的create类的方法Shop。这是一个类构造函数和所有对象Shop应仅使用此方法创建,而不是直接调用构造函数。完整代码:

import multiprocess
from multiprocess import Manager, Process
from multiprocess.managers import NamespaceProxy, BaseManager
import types


class ObjProxy(NamespaceProxy):
    """Returns a proxy instance for any user defined data-type. The proxy instance will have the namespace and
    functions of the data-type (except private/protected callables/attributes). Furthermore, the proxy will be
    pickable and can its state can be shared among different processes. """

    def __getattr__(self, name):
        result = super().__getattr__(name)
        if isinstance(result, types.MethodType):
            def wrapper(*args, **kwargs):
                return self._callmethod(name, args, kwargs)
            return wrapper
        return result


class Shop:

    def __init__(self, stock=5):
        self.stock = stock

    @classmethod
    def create(cls, *args, **kwargs):

        # Register class
        class_str = cls.__name__
        BaseManager.register(class_str, cls, ObjProxy, exposed=tuple(dir(cls)))

        # Start a manager process
        manager = BaseManager()
        manager.start()

        # Create and return this proxy instance. Using this proxy allows sharing of state between processes.
        inst = eval("manager.{}(*args, **kwargs)".format(class_str))
        return inst

    def get_item(self, l, x):
        with l:
            if self.stock >= x:
                self.stock -= x
                print(f"{self.stock} = remaining")

    def k(self, l, n):
        pass


if __name__ == "__main__":
    manager = Manager()
    l = manager.Lock()
    obj = Shop.create()
    p1 = Process(target=obj.get_item, args=(l, 1, ))
    p2 = Process(target=obj.get_item, args=(l, 1, ))
    p3 = Process(target=obj.get_item, args=(l, 1, ))

    p1.start()
    p2.start()
    p3.start()

    p1.join()
    p2.join()
    p3.join()

    print("Final: ", obj.stock) 

Output

4 = remaining
3 = remaining
2 = remaining
Final:  2

Note:这两行的解释:

manager = Manager()
l = manager.Lock()

在您的示例中概述了我们之前不需要为锁创建管理器(以及随后的代理)的原因here。之所以在不创建代理的情况下使用上面的代码不起作用,是因为我们不再在主进程中创建进程,并且当前进程内存空间中不存在锁(自从为我们的复杂对象创建管理器以来)共享其状态产生了自己的服务器进程)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么Multiprocessing的Lock不会阻止其他进程使用对象? 的相关文章

  • 现在与出生日期之间的年、月、日、分钟差异

    import datetime birthday datetime datetime 1996 8 15 differnce datetime datetime now birthday This returns a timedelta o
  • 无法使用 beautifulsoup 模块 python 从 HTML 检索温度值

    我正在使用 BeautifulSoup4 来解析此 HTML 查看源代码 https weather com en IN weather today l 17 39 78 49 https weather com en IN weather
  • 我无法使用 Python 和 Facebook Marketing API 获取所有 Facebook 营销活动的统计信息

    我正在尝试检索以下指标 date campaign name impressions clicks spend 在我的 Facebook 帐户中的所有活动中 但显然我编写的脚本仅返回某些活动的统计数据 而不是全部 它仅返回大多数营销活动的营
  • Python3如何安装.ttf字体文件?

    我想使用 python3 更精确的 Python 3 6 代码在 Windows 10 上安装 ttf 字体文件 我用谷歌搜索 但我发现的唯一的就是这个使用python在windows上安装TTF字体 https stackoverflow
  • 如何在离线绘图中绘制垂直线?

    如何使用 python 以离线方式绘制一条垂直线 我想在 x 20 x 40 和 x 60 处添加线条 所有线条都在同一个图中 def graph contracts self trace1 go Scatter x np array ra
  • pandas 在单元格中缩写字典

    我有一个相当复杂的嵌套字典 它使用 pandas 很好地打印为 html 但是 有一个字典作为打印在单元格中的值之一 如下所示 pd set option display max colwidth 1 已设置 所以这不应该是问题 这是产生问
  • 如何将交互式 matplotlib 图形插入 tkinter 画布

    我正在尝试将交互式 matplotlib 图形 具有滑块 重置按钮和单选按钮的图形 放入 tkinter Canvas 中 我已成功添加非交互式图表 但当它变为交互式时找不到问题 我尝试将所有内容更改为使用 matplotlib Figur
  • 如何添加 id 列来标识 read_html() 表?

    考虑以下站点 site1 http pastebin com vpnGqn5X site2 http pastebin com FbAFGbfR site3 http pastebin com LqZWxFSP 其中有许多不同的表 我在用读
  • 如何向 scikit-learn KD 树添加/删除数据点?

    我想知道是否可以在创建 scikit learn KDTree 实例后添加或删除数据点 例如 from sklearn neighbors import KDTree import numpy as np X np array 1 1 2
  • 如何在 Detectron2 中计算并集交集?

    我正在使用 Detectron2 进行对象检测 我已经注册了 pascalvoc 数据集并训练了一个检测模型 如何计算测试数据集的平均 IOU 我知道 detector2 有一个用于计算 IOU 的预定义函数 即 detectorron2
  • 在 pywin32 中创建一个新的 Excel 文件

    我正在编写一个程序 概括来说 采用记事本文件并将其另存为 Excel 文件 现在我的程序打开一个我创建的空白 Excel 文件 只是 Book1 xls xlApp Dispatch Excel Application xlApp Visi
  • 导入错误:无法导入名称“FFProbe”

    我无法获取ffprobe包 https github com simonh10 ffprobe在 Python 3 6 中工作 我使用 pip 安装它 但是当我输入import ffprobe it says Traceback most
  • 可升级读锁的优点?

    我想知道使用可升级读锁与执行这些步骤相比有什么优势 获取读锁 检查条件以查看是否需要进行写锁定 释放读锁 采取写锁定 执行更新 释放写锁 与获取可升级读锁相比 执行上述步骤的一个明显缺点是 步骤 3 和步骤 4 之间存在一个时间窗口 其中另
  • 哪种方式最适合Python工厂注册?

    这是一个关于这些方法中哪一种被认为是最有效的问题 Pythonic 我不是在寻找个人意见 而是在寻找惯用的观点 我的背景不是Python 所以这会对我有帮助 我正在开发一个可扩展的 Python 3 项目 这个想法类似于工厂模式 只不过它是
  • 检查 IP 地址是否在给定范围内

    我想检查一下是否有IP180 179 77 11位于特定范围之间 例如180 179 0 0 180 179 255 255 我编写了一个函数 它将每个 IP 八位字节与其他八位字节进行比较 def match mask IP min ip
  • Python 3 中 int() 和 Floor() 有什么区别?

    在Python 2中 floor 返回一个浮点值 虽然对我来说并不明显 但我发现了一些解释来澄清为什么它可能有用floor 返回浮点数 对于类似的情况float inf and float nan 然而 在Python 3中 floor 返
  • 加载pickle时出错

    无法加载 pickle 文件 我正在使用 python 3 5 import pickle data pickle load open D ud120 projects final project final project dataset
  • 当在Python中使用负数对字符串进行切片时,0被禁用?

    假设我有一个字符串 gt gt gt a akwkwas gt gt gt gt gt gt a 3 was gt gt gt a 3 None was gt gt gt a 3 0 为什么我不能使用0作为切片的末尾 这是来自文档 记住切片
  • 来自 dll 的 Java 调用函数

    我有这个 python 脚本导入zkemkeeperdll 并连接到考勤设备 ZKTeco 这是我正在使用的脚本 from win32com client import Dispatch zk Dispatch zkemkeeper ZKE
  • 无效的选择器:使用 Selenium 时不允许出现复合类名错误

    我正在尝试通过 Web Whatsapp 打印聊天中的一条消息 我可以通过 控制台 选项卡中的 Javascript 来完成此操作 我就是这样做的 recived msg document getElementsByClassName XE

随机推荐

  • Python 和 sqlite3 抛出错误:sqlite3.OperationalError:靠近“s”:语法错误

    我正在尝试使用 Python 和 BeautifulSoup 来抓取一些网络信息 迭代它 然后将一些片段插入 sqlite3 数据库中 但我不断出现这个错误 TBTscrape 中的文件 Users Chris Desktop BS4 TB
  • Azure:跨多个资源组共享资源

    是否可以在多个资源组之间共享特定资源 在我的例子中是 redis 缓存 资源组只是逻辑容器 资源位于哪个资源组中并不重要 您可以使用任何资源组中的资源 Example 假设您在 RG1 中创建应用服务计划 并在 RG2 中创建 Web 应用
  • Swift 3 中是否可以在不自动布局的情况下降低键盘的高度?

    我需要以编程方式降低键盘的高度 我有什么办法可以做到吗 我发现我们可以使用键盘扩展来降低高度 但我尝试过 但它对我不起作用 我有什么办法可以做到这一点吗 Edit But i can see small keyboards in some
  • 如何替换字符串的某些部分?

    如何用另一部分替换字符串的某一部分 输入字符串 Hello my name is Santa 我怎样才能改变一切a在我的字符串中还有其他东西吗 我想我需要一个foreach循环 但我不确定如何使用它 strtr str array a gt
  • java下载文件时如何检测网络断开?

    我正在使用以下代码使用 Java 下载文件 但我想检测连接何时丢失 我运行了以下代码 在下载过程中我故意断开了互联网连接 但没有引发异常并且挂起 即使打开连接后也没有任何反应 于是 它就永远挂了 没有任何例外 有没有办法让它在连接丢失时抛出
  • 我可以仅在底部椭圆化剪贴蒙版吗?

    我正在尝试在 CSS 中的图像上创建弯曲的剪贴蒙版 该曲线本质上只是一个非常宽的椭圆的下半部分 要求是角度 曲率不会根据图像的高度 宽度而改变 它应该始终保持一致 这是一个视觉效果 尝试1 边框半径 溢出隐藏 固定宽度 问题 图像高度影响曲
  • 为什么“cut”反对我的标签?

    我试图根据值所属的范围来标记值 就像你对作业评分一样 因此 如果我有一个平均测验分数的数据框和一个数值数据框 我将其用作为这些平均值分配分数的下限 grades lt read table text Student Mean Adam 94
  • 私人运营商删除[重复]

    这个问题在这里已经有答案了 可能的重复 公共运算符 new 私有运算符删除 使用 new 时出现 C2248 无法访问私有成员 http efesx com 2009 12 01 public operator new and privat
  • jQuery addClass 方法链接以执行 CSS 转换

    我想做的事 broke div div
  • 通过java App查看PDF

    我想知道如何通过 Java 应用程序查看 PDF 我正在尝试创建一个应用程序来使用 NetBeans 6 8 查看 PDF 很少有 pdf 阅读器库 例如 iText pdfBox 但他们没有帮助我 请帮我 任何帮助都是感激的 谢谢你 这里
  • Spring集成:使用oubound网关处理http错误

    如何处理 http 出站网关中的异常 当我收到状态代码 500 或 400 时 会显示异常 那么我应该如何使用 spring 集成来处理 http 错误 我的配置是这样的
  • 将 JSON 从 ajax 发布到 Struts2 Action

    嘿 我正在尝试将 JSON 从 Ajax 发布到 Struts2 操作类方法 更多信息 我在 WAMP 服务器上运行客户端 在 Eclipse Tomcat 上运行 Struts2 我的客户端代码
  • Vue.js项目中添加Tailwind.css后,某些类没有效果

    我正在尝试将 Tailwind css 添加到 Vue js 项目中 有很多关于如何执行此操作的资源 其中大多数都遵循与这个视频 为了确保我处于与视频中相同的条件 我从头开始创建了一个 Vue 应用程序 使用vue cli使用默认预设 完成
  • 使用脚本在 Powershell 命令提示符中填写多个答案

    我正在尝试使用 Powershell 脚本自动填写提示的答案 提示问题如下所示 这些问题由 cmd 文件一个接一个地生成 这意味着输入不会返回到 Powershell 输入 我找到了很多答案来一次回答一个问题或多个是 否问题 但还没有这样的
  • .NET WebAPI集中授权

    在 NET WebAPI 中 我创建了一种将所有授权规则放在一个中央位置的方法 而不是分散在各个控制器中 我很好奇为什么这种集中化没有更频繁地进行 是否有影响 安全问题 我当前的方法是在 App Start 期间创建一个字典 其中包含我的所
  • 如何在我的应用程序中使用密码锁定场景?

    实际上 我构建了一个包含本地身份验证的应用程序 到目前为止我的代码 func authenticateUser let authenticationContext LAContext var error NSError let reason
  • 类中函数原型中的运算符 & 和 *

    我在这样的课程中遇到问题 class Sprite bool checkCollision Sprite spr 所以 如果我有这门课 我可以这样做 ball checkCollision bar1 但如果我将课程更改为 class Spr
  • 用于解压缩文件的 VBA 脚本 - 只是创建空文件夹

    我正在使用 Ron 的代码 http www rondebruin nl win s7 win002 htm 理论上可以将一堆 zip 文件解压到一个文件夹中 我相信下面的代码获取 下载 目录中的每个 zip 文件 使用 zip 文件的名称
  • 如何用selenium继续填充下一页的数据?

    我想通过以下方式登录Selenium 该过程分为2页 email 密码 现在我可以在第一页输入密钥 然后我应该进入下一页 输入密码并单击提交密钥 但是 如果我只在一个类中添加4个按键代码 则无法完成第二页按键输入 密码和提交 我猜想第一页按
  • 为什么Multiprocessing的Lock不会阻止其他进程使用对象?

    以下代码是一家商店的代码 该商店有 5 件商品 三个顾客各需要一件商品 import multiprocessing as mp class Shop def init self stock 5 self stock stock def g