python 多线程 廖雪峰_python中多线程与多进程中的数据共享问题

之前在写多线程与多进程的时候,因为一般情况下都是各自完成各自的任务,各个子线程或者各个子进程之前并没有太多的联系,如果需要通信的话我会使用队列或者数据库来完成,但是最近我在写一些多线程与多进程的代码时,发现如果它们需要用到共享变量的话,需要有一些注意的地方

多线程之间的共享数据

标准数据类型在线程间共享

看以下代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14#coding:utf-8

import threading

def test(name,data):

print("in thread {} name is {}".format(threading.current_thread(),name))

print("data is {} id(data) is {}".format(data,id(data)))

if __name__ == '__main__':

d = 5

name = "杨彦星"

for i in range(5):

th = threading.Thread(target=test,args=(name,d))

th.start()

这里我创建一个全局的int变量d,它的值是5,当我在5个线程中调用test函数时,将d作为参数传进去,那么这5个线程所拥有的是同一个d吗?我在test函数中通过id(data) 来打印一下它们的ID,得到了如下的结果

1

2

3

4

5

6

7

8

9

10in thread name is 杨彦星

data is 5 id(data) is 1763791776

in thread name is 杨彦星

data is 5 id(data) is 1763791776

in thread name is 杨彦星

data is 5 id(data) is 1763791776

in thread name is 杨彦星

data is 5 id(data) is 1763791776

in thread name is 杨彦星

data is 5 id(data) is 1763791776

从结果中可以看到,在5个子线程中,data的id都是1763791776,说明在主线程中创建了变量d,在子线程中是可以共享的,在子线程中对共享元素的改变是会影响到其它线程的,所以如果要对共享变量进行修改时,也就是线程不安全的,需要加锁。

自定义类型对象在线程间共享

如果我们要自定义一个类呢,将一个对象作为变量在子线程中传递呢?会是什么效果呢?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25#coding:utf-8

import threading

class Data:

def __init__(self,data=None):

self.data = data

def get(self):

return self.data

def set(self,data):

self.data = data

def test(name,data):

print("in thread {} name is {}".format(threading.current_thread(),name))

print("data is {} id(data) is {}".format(data.get(),id(data)))

if __name__ == '__main__':

d = Data(10)

name = "杨彦星"

print("in main thread id(data) is {}".format(id(d)))

for i in range(5):

th = threading.Thread(target=test,args=(name,d))

th.start()

这里我定义一个简单的类,在主线程初始化了一个该类型的对象d,然后将它作为参数传给子线程,主线程和子线程分别打印了这个对象的id,我们来看一下结果

1

2

3

4

5

6

7

8

9

10

11in main thread id(data) is 2849240813864

in thread name is 杨彦星

data is 10 id(data) is 2849240813864

in thread name is 杨彦星

data is 10 id(data) is 2849240813864

in thread name is 杨彦星

data is 10 id(data) is 2849240813864

in thread name is 杨彦星

data is 10 id(data) is 2849240813864

in thread name is 杨彦星

data is 10 id(data) is 2849240813864

我们看到,在主线程和子线程中,这个对象的id是一样的,说明它们用的是同一个对象。

无论是标准数据类型还是复杂的自定义数据类型,它们在多线程之间是共享同一个的,但是在多进程中是这样的吗?

多进程之间的共享数据

标准数据类型在进程间共享

还是上面的代码,我们先来看一下int类型的变量的子进程间的共享

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16#coding:utf-8

import threading

import multiprocessing

def test(name,data):

print("in thread {} name is {}".format(threading.current_thread(),name))

print("data is {} id(data) is {}".format(data,id(data)))

if __name__ == '__main__':

d = 10

name = "杨彦星"

print("in main thread id(data) is {}".format(id(d)))

for i in range(5):

pro = multiprocessing.Process(target=test,args=(name,d))

pro.start()

得到的结果是

1

2

3

4

5

6

7

8

9

10

11in main thread id(data) is 1763791936

in thread <_mainthread started> name is 杨彦星

data is 10 id(data) is 1763791936

in thread <_mainthread started> name is 杨彦星

data is 10 id(data) is 1763791936

in thread <_mainthread started> name is 杨彦星

data is 10 id(data) is 1763791936

in thread <_mainthread started> name is 杨彦星

data is 10 id(data) is 1763791936

in thread <_mainthread started> name is 杨彦星

data is 10 id(data) is 1763791936

可以看到它们的id是一样的,说明用的是同一个变量,但是当我尝试把d由int变为了string时,发现它们又不一样了……

1

2

3

4

5

6

7if __name__ == '__main__':

d = 'yangyanxing'

name = "杨彦星"

print("in main thread id(data) is {}".format(id(d)))

for i in range(5):

pro = multiprocessing.Process(target=test,args=(name,d))

pro.start()

此时得到的结果是

1

2

3

4

5

6

7

8

9

10

11in main thread id(data) is 2629633397040

in thread <_mainthread started> name is 杨彦星

data is yangyanxing id(data) is 1390942032880

in thread <_mainthread started> name is 杨彦星

data is yangyanxing id(data) is 2198251377648

in thread <_mainthread started> name is 杨彦星

data is yangyanxing id(data) is 2708672287728

in thread <_mainthread started> name is 杨彦星

data is yangyanxing id(data) is 2376058999792

in thread <_mainthread started> name is 杨彦星

data is yangyanxing id(data) is 2261044040688

于是我又尝试了list、Tuple、dict,结果它们都是不一样的,我又回过头来试着在多线程中使用列表元组和字典,结果在多线程中它们的id还是一样的。

这里有一个有趣的问题,如果是int类型,当值小于等于256时,它们在多进程间的id是相同的,如果大于256,则它们的id就会不同了,这个我没有查看原因。

自定义类型对象在进程间共享1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26#coding:utf-8

import threading

import multiprocessing

class Data:

def __init__(self,data=None):

self.data = data

def get(self):

return self.data

def set(self,data):

self.data = data

def test(name,data):

print("in thread {} name is {}".format(threading.current_thread(),name))

print("data is {} id(data) is {}".format(data.get(),id(data)))

if __name__ == '__main__':

d = Data(10)

name = "杨彦星"

print("in main thread id(data) is {}".format(id(d)))

for i in range(5):

pro = multiprocessing.Process(target=test,args=(name,d))

pro.start()

得到的结果是

1

2

3

4

5

6

7

8

9

10

11in main thread id(data) is 1927286591728

in thread <_mainthread started> name is 杨彦星

data is 10 id(data) is 1561177927752

in thread <_mainthread started> name is 杨彦星

data is 10 id(data) is 2235260514376

in thread <_mainthread started> name is 杨彦星

data is 10 id(data) is 2350586073040

in thread <_mainthread started> name is 杨彦星

data is 10 id(data) is 2125002248088

in thread <_mainthread started> name is 杨彦星

data is 10 id(data) is 1512231669656

可以看到它们的id是不同的,也就是不同的对象。

在多进程间如何共享数据

我们看到,数据在多进程间是不共享的(小于256的int类型除外),但是我们又想在主进程和子进程间共享一个数据对象时该如何操作呢?

在看这个问题之前,我们先将之前的多线程代码做下修改

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34#coding:utf-8

import threading

import multiprocessing

class Data:

def __init__(self,data=None):

self.data = data

def get(self):

return self.data

def set(self,data):

self.data = data

def test(name,data,lock):

lock.acquire()

print("in thread {} name is {}".format(threading.current_thread(),name))

print("data is {} id(data) is {}".format(data,id(data)))

data.set(data.get()+1)

lock.release()

if __name__ == '__main__':

d = Data(0)

thlist = []

name = "yang"

lock = threading.Lock()

for i in range(5):

th = threading.Thread(target=test,args=(name,d,lock))

th.start()

thlist.append(th)

for i in thlist:

i.join()

print(d.get())

我们这个代码的目的是这样,使用自定义的Data类型对象,当经过5个子线程操作以后,每个子线程对其data值进行加1操作,最后在主线程打印对象的data值。

该输出结果如下

1

2

3

4

5

6

7

8

9

10

11in thread name is yang

data is <__main__.data object at> id(data) is 1805246501272

in thread name is yang

data is <__main__.data object at> id(data) is 1805246501272

in thread name is yang

data is <__main__.data object at> id(data) is 1805246501272

in thread name is yang

data is <__main__.data object at> id(data) is 1805246501272

in thread name is yang

data is <__main__.data object at> id(data) is 1805246501272

5

可以看到在主线程最后打印出来了5,符合我们的预期,但是如果放到多进程中呢?因为多进程下,每个子进程所持有的对象是不同的,所以每个子进程操作的是各自的Data对象,对于主进程的Data对象应该是没有影响的,我们来看下它的结果

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34#coding:utf-8

import threading

import multiprocessing

class Data:

def __init__(self,data=None):

self.data = data

def get(self):

return self.data

def set(self,data):

self.data = data

def test(name,data,lock):

lock.acquire()

print("in thread {} name is {}".format(threading.current_thread(),name))

print("data is {} id(data) is {}".format(data,id(data)))

data.set(data.get()+1)

lock.release()

if __name__ == '__main__':

d = Data(0)

thlist = []

name = "yang"

lock = multiprocessing.Lock()

for i in range(5):

th = multiprocessing.Process(target=test,args=(name,d,lock))

th.start()

thlist.append(th)

for i in thlist:

i.join()

print(d.get())

它的输出结果是:

1

2

3

4

5

6

7

8

9

10

11in thread <_mainthread started> name is yang

data is <__mp_main__.data object at> id(data) is 1997429477048

in thread <_mainthread started> name is yang

data is <__mp_main__.data object at> id(data) is 3044738469504

in thread <_mainthread started> name is yang

data is <__mp_main__.data object at> id(data) is 2715076202224

in thread <_mainthread started> name is yang

data is <__mp_main__.data object at> id(data) is 2482736991872

in thread <_mainthread started> name is yang

data is <__mp_main__.data object at> id(data) is 1861188783744

0

最后的输出是0,说明了子进程对于主进程传入的Data对象操作其实对于主进程的对象是不起作用的,我们需要怎样的操作才能实现子进程可以操作主进程的对象呢?我们可以使用multiprocessing.managers 下的 BaseManager 来实现

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45#coding:utf-8

import threading

import multiprocessing

from multiprocessing.managers import BaseManager

class Data:

def __init__(self,data=None):

self.data = data

def get(self):

return self.data

def set(self,data):

self.data = data

BaseManager.register("mydata",Data)

def test(name,data,lock):

lock.acquire()

print("in thread {} name is {}".format(threading.current_thread(),name))

print("data is {} id(data) is {}".format(data,id(data)))

data.set(data.get()+1)

lock.release()

def getManager():

m = BaseManager()

m.start()

return m

if __name__ == '__main__':

manager = getManager()

d = manager.mydata(0)

thlist = []

name = "yang"

lock = multiprocessing.Lock()

for i in range(5):

th = multiprocessing.Process(target=test,args=(name,d,lock))

th.start()

thlist.append(th)

for i in thlist:

i.join()

print(d.get())

使用from multiprocessing.managers import BaseManager 引入 BaseManager以后,在定义完Data类型之后,使用BaseManager.register("mydata",Data) 将Data类型注册到BaseManager中,并且给了它一个名字叫mydata,之后就可以使用BaseManager对象的这个名字来初始化对象,我们来看一下输出

1

2

3

4

5

6

7

8

9

10

11

12C:\Python35\python.exe F:/python/python3Test/multask.py

in thread <_mainthread started> name is yang

data is <__mp_main__.data object at> id(data) is 2222932504080

in thread <_mainthread started> name is yang

data is <__mp_main__.data object at> id(data) is 1897574510096

in thread <_mainthread started> name is yang

data is <__mp_main__.data object at> id(data) is 2053415775760

in thread <_mainthread started> name is yang

data is <__mp_main__.data object at> id(data) is 2766155820560

in thread <_mainthread started> name is yang

data is <__mp_main__.data object at> id(data) is 2501159890448

5

我们看到,虽然在每个子进程中使用的是不同的对象,但是它们的值却是可以“共享”的。

标准的数据类型也可以通过multiprocessing库中的Value对象,举一个简单的例子

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38#coding:utf-8

import threading

import multiprocessing

from multiprocessing.managers import BaseManager

class Data:

def __init__(self,data=None):

self.data = data

def get(self):

return self.data

def set(self,data):

self.data = data

BaseManager.register("mydata",Data)

def test(name,data,lock):

lock.acquire()

print("in thread {} name is {}".format(threading.current_thread(),name))

print("data is {} id(data) is {}".format(data,id(data)))

data.value +=1

lock.release()

if __name__ == '__main__':

d = multiprocessing.Value("l",10) #

print(d)

thlist = []

name = "yang"

lock = multiprocessing.Lock()

for i in range(5):

th = multiprocessing.Process(target=test,args=(name,d,lock))

th.start()

thlist.append(th)

for i in thlist:

i.join()

print(d.value)

这里使用d = multiprocessing.Value("l",10) 初始化了一个数字类型的对象,这个类型是Synchronized wrapper for c_long ,multiprocessing.Value在初始化时,第一个参数是类型,第二个参数是值,具体支持的类型如下

还可以使用ctypes库里和类初始化字符串

1

2

3

4>>>from ctypes import c_char_p

>>>s = multiprocessing.Value(c_char_p, b'\xd1\xee\xd1\xe5\xd0\xc7')

>>>print(s.value.decode('gbk'))

杨彦星

还可以使用Manager对象初始list,dict等

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26#coding:utf-8

import multiprocessing

def func(mydict, mylist):

# 子进程改变dict,主进程跟着改变

mydict["index1"] = "aaaaaa"

# 子进程改变List,主进程跟着改变

mydict["index2"] = "bbbbbb"

mylist.append(11)

mylist.append(22)

mylist.append(33)

if __name__ == "__main__":

# 主进程与子进程共享这个字典

mydict = multiprocessing.Manager().dict()

# 主进程与子进程共享这个List

mylist = multiprocessing.Manager().list(range(5))

p = multiprocessing.Process(target=func, args=(mydict, mylist))

p.start()

p.join()

print(mylist)

print(mydict)

其实我们这里所说的共享只是数据值上的共享,因为在多进程中,各自持有的对象都不相同,所以如果想要同步状态需要曲线救国。不过这种在自己写的小项目中可以简单的使用,如果做一些大一点的项目,还是建议不要使用这种共享数据的方式,这种大大的增加了程序间的耦合性,使用逻辑变得复杂难懂,所以建议还是使用队列或者数据库作为通信的渠道。

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

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

相关文章

填平数据、产品、模式需求鸿沟,浪潮云发布新一代行业云 MEP战略

围绕安全这一核心&#xff0c;浪潮云从新模式&#xff08;New Model&#xff09;、新要素&#xff08;New Essential Factor&#xff09;、新产品&#xff08;New Product&#xff09;三大方面出发&#xff0c;提出新一代行业云MEP战略。 出品 | CSDN云计算 12月16日&#xff0…

hpsocket java代码_HPSocket介绍与使用

一、HPSocket介绍HP-Socket是一套通用的高性能TCP/UDP/HTTP 通信框架&#xff0c;包含服务端组件、客户端组件和Agent组件&#xff0c;广泛适用于各种不同应用场景的TCP/UDP/HTTP通信系统&#xff0c;提供C/C、C#、Delphi、E(易语言)、Java、Python等编程语言接口。HP-Socket对…

Dapr 在阿里云原生的实践

简介&#xff1a; Faas 场景下&#xff0c;比较吸引用户的是成本和研发效率&#xff0c;成本主要通过按需分配和极致的弹性效率来达成。而应用开发者期望通过 FaaS 提供多语言的编程环境&#xff0c;提升研发效率&#xff0c;包括启动时间、发布时间、开发的效率。​ 作者&…

postgre 生成数据库html文档_还在手动整理数据库文档?试试这个(螺丝钉)数据库文档生成工具...

简介在企业级开发中、我们经常会有编写数据库表结构文档的时间付出&#xff0c;从业以来&#xff0c;待过几家企业&#xff0c;关于数据库表结构文档状态&#xff1a;要么没有、要么有、但都是手写、后期运维开发&#xff0c;需要手动进行维护到文档中&#xff0c;很是繁琐、如…

OpenFaaS - 以自己的方式运行容器化函数

作者 | Addo Zhang来源 | 云原生指北译者注&#xff1a; 本文篇幅较长&#xff0c;有助于了解 FaaS 和 OpenFaaS。作者分别从开发人员和运维人员的视角来了解 OpenFaaS&#xff0c;对了解新的技术是个很好的方式。本文翻译自 Ivan Velichko[1] 的 OpenFaaS - Run Containerized…

技术人生第5篇——浅谈如何成为技术一号位?

简介&#xff1a; 认清每个人自己在日常工作中的思维定式非常重要&#xff0c;有助于转变自己对很多事情的认知&#xff0c;而这种转变也会从根本上带来行为上的变化。也就是说&#xff0c;可以通过理论分析和实践&#xff0c;来共同完成对个人实际生活的影响。今天这篇文章&am…

元宇宙真的是「割韭菜」吗?

作者 | 小枣君来源 | 鲜枣课堂我们究竟该如何看待元宇宙&#xff1f;元宇宙为什么会火&#xff1f;它到底有没有价值&#xff1f;它真的是“割韭菜”吗&#xff1f;今天这篇文章&#xff0c;小枣君想说说自己的看法。█ 元宇宙为什么会火&#xff1f;元宇宙的蹿红速度&#xff…

阿里仿真灰度变更测试简介

简介&#xff1a; 基础网络产品的生命周期大致包含研发、架构、交付、优化和运营等几个环节&#xff0c;每一个环节的质量保证都涉及重要的一环&#xff0c;即预期验证测试。本文将重点讲解一下如何在仿真测试平台进行灰度变更测试&#xff0c;从而保证变更的稳定性。 作者 | 聪…

树莓派开始玩转linux pdf_用树莓派构建 Kubernetes 集群 | Linux 中国

将 Kubernetes 安装在多个树莓派上&#xff0c;实现自己的“家庭私有云”容器服务。• 来源&#xff1a;linux.cn • 作者&#xff1a;Chris Collins • 译者&#xff1a;Xingyu.Wang •(本文字数&#xff1a;14330&#xff0c;阅读时长大约&#xff1a;18 分钟)将 Kubernetes …

非标准化的阀门企业也在用钉钉宜搭实现数字化转型

简介&#xff1a; 增长对于所有企业来说&#xff0c;都是机遇与挑战并存。对非标准化的制造企业来说&#xff0c;增长是一把双刃剑&#xff0c;它既是订单增长带来的销售提升&#xff0c;同时在另一边则往往是“低效与浪费”的困扰。 困扰非标制造业的两大难题 1、增长期的“…

慢SQL治理分享

简介&#xff1a; 这里的慢SQL指的是MySQL慢查询&#xff0c;是运行时间超过long_query_time值的SQL。真实的慢SQL通常会伴随着大量的行扫描、临时文件排序或者频繁的磁盘flush&#xff0c;直接影响就是磁盘IO升高&#xff0c;让正常的SQL变成了慢SQL&#xff0c;大面积执行超时…

英特尔表示:元宇宙的路还很长

编译 | 禾木木出品 | CSDN云计算&#xff08;ID&#xff1a;CSDNcloud&#xff09;现在每个人都在谈论元宇宙&#xff0c;各大公司也都在致力于访问它的硬件&#xff0c;而且它似乎最终可能成为万维网规模的下一个主要通信平台。但如果你问的话&#xff0c;「最终」还是有很长的…

java csv 追加_如何在Java中添加一个包含CSV数据的列

基于plirke示例代码和他的帮助,我编写了一个最终的工作代码。在这里分享它,这样它可能对有类似需求的人有用。import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileReader;import java.io.FileWriter;import java.io.IOExcep…

案例|自建or现成工具?小型创业团队敏捷研发探索

简介&#xff1a; 实践和踩坑建议。 我是刘永良&#xff0c;是一名全栈开发者也是一名创业者&#xff0c;来自济南——一个目前被称为互联网洼地的地方。2020年4月和三位志同道合的朋友&#xff0c;在济南共同创建了山东旷野网络科技有限公司&#xff0c;主要从事自有项目和外包…

代码智能技术如何应用到日常开发?

简介&#xff1a; 原理与演示。 01/ 从开发者的烦恼说起 开发者在编写代码时&#xff0c;需要花费大量时间在低层次的重复编码上&#xff0c;特别是针对一些语法比较冗余的开发语言。 同时&#xff0c;开发者经常被戏称为面向搜索引擎编程&#xff0c;因为我们经常需要通过…

sql server tcp 信号灯超时时间已到_「图文详解」TCP为啥要3次握手和4次挥手?3次挥手不行吗?...

原文链接&#xff1a;https://www.cnblogs.com/qdhxhz/p/8470997.htmlTCP有6种标示:SYN(建立联机) ACK(确认) PSH(传送) FIN(结束) RST(重置) URG(紧急)一、TCP三次握手第一次握手客户端向服务器发出连接请求报文&#xff0c;这时报文首部中的同部位SYN1&#xff0c;同时随机生…

F5:2022年应用交付和安全领域趋势展望

作者 | F5中国区金融事业部技术总监兼安全事业部副总经理 陈亮 出品 | CSDN 云计算 随着人工智能&#xff08;AI)、物联网 (IoT)等技术的日益普及&#xff0c;企业拥抱互联网技术的程度不断提高&#xff0c;越来越多的企业开始考虑利用数字化来提升劳动生产率和利用电子商务扩…

java的class文件在哪里_传统上,你在哪里存储Java .class文件?

如果你不熟悉它,你应该研究Java classpath的主题.我记得当我第一次开始用Java编程时发现这个令人困惑.Java中有.class文件的定义搜索路径;当你运行设置类路径的java -cp blahblahblah时. java -jar blahblahblah.jar打开一个JAR file,.jar文件的清单可以指示类路径.默认的类路径…

DevOps 能力提升模型

简介&#xff1a; DevOps 能力反映的是技术研发响应业务变化的能力。随着组织规模的增加和业务复杂性增长&#xff0c;DevOps 能力会变得越来越重要。持续提升 DevOps 的能力成为技术研发的共同挑战。 编者按&#xff1a;本文源自阿里云云效团队出品的《阿里巴巴DevOps实践指南…

生态和场景一站式集成?来看看小程序的“共享主义”

简介&#xff1a; mPaaS 小程序市场正式上线&#xff0c;海量小程序一站式集成&#xff0c;用场景拉高终端活跃水位。 01 小程序破壁计划 从 2018 年「支付宝」将支付宝小程序全量开放给用户使用开始&#xff0c;整个小程序生态市场发生了新一波的震荡。 小程序商家通过「支付…