亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

處理python中多線程與多進程中的數據共享問題

系統 1549 0

之前在寫多線程與多進程的時候,因為一般情況下都是各自完成各自的任務,各個子線程或者各個子進程之前并沒有太多的聯系,如果需要通信的話我會使用隊列或者數據庫來完成,但是最近我在寫一些多線程與多進程的代碼時,發現如果它們需要用到共享變量的話,需要有一些注意的地方

多線程之間的共享數據

標準數據類型在線程間共享

看以下代碼

            
#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,得到了如下的結果

            
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
in thread 
                    
                       name is 楊彥星
data is 5 id(data) is 1763791776
                    
                  
                
              
            
          

從結果中可以看到,在5個子線程中,data的id都是1763791776,說明在主線程中創建了變量d,在子線程中是可以共享的,在子線程中對共享元素的改變是會影響到其它線程的,所以如果要對共享變量進行修改時,也就是線程不安全的,需要加鎖。

自定義類型對象在線程間共享

如果我們要自定義一個類呢,將一個對象作為變量在子線程中傳遞呢?會是什么效果呢?

            
#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,我們來看一下結果

            
in 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類型的變量的子進程間的共享

            
#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()
          

得到的結果是

            
in main thread id(data) is 1763791936
in thread <_MainThread(MainThread, started 9364)> name is 楊彥星
data is 10 id(data) is 1763791936
in thread <_MainThread(MainThread, started 9464)> name is 楊彥星
data is 10 id(data) is 1763791936
in thread <_MainThread(MainThread, started 3964)> name is 楊彥星
data is 10 id(data) is 1763791936
in thread <_MainThread(MainThread, started 10480)> name is 楊彥星
data is 10 id(data) is 1763791936
in thread <_MainThread(MainThread, started 13608)> name is 楊彥星
data is 10 id(data) is 1763791936
          

可以看到它們的id是一樣的,說明用的是同一個變量,但是當我嘗試把d由int變為了string時,發現它們又不一樣了……

            
if __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()
          

此時得到的結果是

            
in main thread id(data) is 2629633397040
in thread <_MainThread(MainThread, started 9848)> name is 楊彥星
data is yangyanxing id(data) is 1390942032880
in thread <_MainThread(MainThread, started 988)> name is 楊彥星
data is yangyanxing id(data) is 2198251377648
in thread <_MainThread(MainThread, started 3728)> name is 楊彥星
data is yangyanxing id(data) is 2708672287728
in thread <_MainThread(MainThread, started 5288)> name is 楊彥星
data is yangyanxing id(data) is 2376058999792
in thread <_MainThread(MainThread, started 12508)> name is 楊彥星
data is yangyanxing id(data) is 2261044040688
          

于是我又嘗試了list、Tuple、dict,結果它們都是不一樣的,我又回過頭來試著在多線程中使用列表元組和字典,結果它們還是一樣的。

這里有一個有趣的問題,如果是int類型,當值小于等于256時,它們在多進程間的id是相同的,如果大于256,則它們的id就會不同了,這個我沒有查看原因。

自定義類型對象在進程間共享

            
#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()
          

得到的結果是

            
in main thread id(data) is 1927286591728
in thread <_MainThread(MainThread, started 2408)> name is 楊彥星
data is 10 id(data) is 1561177927752
in thread <_MainThread(MainThread, started 5728)> name is 楊彥星
data is 10 id(data) is 2235260514376
in thread <_MainThread(MainThread, started 1476)> name is 楊彥星
data is 10 id(data) is 2350586073040
in thread <_MainThread(MainThread, started 996)> name is 楊彥星
data is 10 id(data) is 2125002248088
in thread <_MainThread(MainThread, started 10740)> name is 楊彥星
data is 10 id(data) is 1512231669656
          

可以看到它們的id是不同的,也就是不同的對象。

在多進程間如何共享數據

我們看到,數據在多進程間是不共享的(小于256的int類型除外),但是我們又想在主進程和子進程間共享一個數據對象時該如何操作呢?

在看這個問題之前,我們先將之前的多線程代碼做下修改

            
#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值。

該輸出結果如下

            
in thread 
            
               name is yang
data is <__main__.Data object at 0x000001A451139198> id(data) is 1805246501272
in thread 
              
                 name is yang
data is <__main__.Data object at 0x000001A451139198> id(data) is 1805246501272
in thread 
                
                   name is yang
data is <__main__.Data object at 0x000001A451139198> id(data) is 1805246501272
in thread 
                  
                     name is yang
data is <__main__.Data object at 0x000001A451139198> id(data) is 1805246501272
in thread 
                    
                       name is yang
data is <__main__.Data object at 0x000001A451139198> id(data) is 1805246501272
                    
                  
                
              
            
          

可以看到在主線程最后打印出來了5,符合我們的預期,但是如果放到多進程中呢?因為多進程下,每個子進程所持有的對象是不同的,所以每個子進程操作的是各自的Data對象,對于主進程的Data對象應該是沒有影響的,我們來看下它的結果

            
#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())
          

它的輸出結果是:

            
in thread <_MainThread(MainThread, started 7604)> name is yang
data is <__mp_main__.Data object at 0x000001D110130EB8> id(data) is 1997429477048
in thread <_MainThread(MainThread, started 12108)> name is yang
data is <__mp_main__.Data object at 0x000002C4E88E0E80> id(data) is 3044738469504
in thread <_MainThread(MainThread, started 3848)> name is yang
data is <__mp_main__.Data object at 0x0000027827270EF0> id(data) is 2715076202224
in thread <_MainThread(MainThread, started 12368)> name is yang
data is <__mp_main__.Data object at 0x000002420EA80E80> id(data) is 2482736991872
in thread <_MainThread(MainThread, started 4152)> name is yang
data is <__mp_main__.Data object at 0x000001B1577F0E80> id(data) is 1861188783744
          

最后的輸出是0,說明了子進程對于主進程傳入的Data對象操作其實對于主進程的對象是不起作用的,我們需要怎樣的操作才能實現子進程可以操作主進程的對象呢?我們可以使用 multiprocessing.managers 下的 BaseManager 來實現

            
#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 對象的這個名字來初始化對象,我們來看一下輸出

            
C:\Python35\python.exe F:/python/python3Test/multask.py
in thread <_MainThread(MainThread, started 12244)> name is yang
data is <__mp_main__.Data object at 0x000001FE1B7D9668> id(data) is 2222932504080
in thread <_MainThread(MainThread, started 2860)> name is yang
data is <__mp_main__.Data object at 0x000001FE1B7D9668> id(data) is 1897574510096
in thread <_MainThread(MainThread, started 2748)> name is yang
data is <__mp_main__.Data object at 0x000001FE1B7D9668> id(data) is 2053415775760
in thread <_MainThread(MainThread, started 7812)> name is yang
data is <__mp_main__.Data object at 0x000001FE1B7D9668> id(data) is 2766155820560
in thread <_MainThread(MainThread, started 2384)> name is yang
data is <__mp_main__.Data object at 0x000001FE1B7D9668> id(data) is 2501159890448
          

我們看到,雖然在每個子進程中使用的是不同的對象,但是它們的值卻是可以“共享”的。

標準的數據類型也可以通過 multiprocessing 庫中的Value對象,舉一個簡單的例子

            
#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庫里和類初始化字符串

            
>>> 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等

            
#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)
          

其實我們這里所說的共享只是數據值上的共享,因為在多進程中,各自持有的對象都不相同,所以如果想要同步狀態需要曲線救國。不過這種在自己寫的小項目中可以簡單的使用,如果做一些大一點的項目,還是建議不要使用這種共享數據的方式,這種大大的增加了程序間的耦合性,使用邏輯變得復雜難懂,所以建議還是使用隊列或者數據為進行間通信的渠道。

總結

以上所述是小編給大家介紹的處理python中多線程與多進程中的數據共享問題,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 精品哟哟国产在线观看 | 九九热在线精品 | 777奇米影视久久激情日韩欧美 | 911精品国产91久久久久 | 四虎精品免费视频 | 色综合小说天天综合网 | 51精品视频在线一区二区 | 久久69精品久久久久久hb | 中文日产国产精品久久 | 日本一区二区视频免费播放 | 国产乱子伦视频大全 | 国产高清精品91在线 | 欧美亚洲第一页 | 国产一区二区三区四区在线 | 操免费视频| 免费精品99久久国产综合精品 | 又爽又黄又无遮挡的视频在线观看 | 高清不卡免费一区二区三区 | 在线亚洲欧洲国产综合444 | 狠狠操大逼 | 亚洲天天在线日亚洲洲精 | 综合图片区 | 日韩精品无码一区二区三区 | 久久国产乱子伦精品免 | 久久99热不卡精品免费观看 | 98色花堂国产精品首页 | 国产产一区二区三区久久毛片国语 | 26uuu在线观看 | 久久国产精品久久精 | 日韩欧美亚洲中字幕在线播放 | 天天躁日日躁狠狠躁黑人躁 | 动漫精品欧美一区二区三区 | 国产99对白在线播放 | 四虎麻豆 | 国产欧美日韩在线观看 | 欧美色综合高清免费 | 欧美一级暴毛片 | 青青久在线视频免费视频 | 酒色网站 | 九九自拍 | 欧美激情视频二区 |