簡體   English   中英

在單獨運行的 Python 腳本之間傳遞數據

[英]Passing data between separately running Python scripts

If I have a python script running (with full Tkinter GUI and everything) and I want to pass the live data it is gathering (stored internally in arrays and such) to another python script, what would be the best way of doing that?

我不能簡單地將腳本 A 導入腳本 B,因為它將創建腳本 A 的新實例,而不是訪問已經運行的腳本 A 中的任何變量。

我能想到的唯一方法是讓腳本 A 寫入文件,然后腳本 B 從文件中獲取數據。 但是,這不太理想,因為如果腳本 B 嘗試讀取腳本 A 已經寫入的文件,則可能會發生一些不好的事情。此外,我正在尋找兩個程序之間更快的通信速度。

編輯:這是所要求的示例。 我知道為什么這不起作用,但這是需要實現的基本前提。 我的源代碼很長而且很遺憾是保密的,所以在這里沒有幫助。 總之,腳本 A 正在運行 Tkinter 並收集數據,而腳本 B 是 views.py 作為 Django 的一部分,但我希望這可以作為 ZA7F5F35426B927411FC9231B5638 的一部分來實現。

腳本 A

import time

i = 0

def return_data():
    return i

if __name__ == "__main__":
    while True:
        i = i + 1
        print i
        time.sleep(.01)

腳本 B

import time
from scriptA import return_data

if __name__ == '__main__':
    while True:
        print return_data()  # from script A
        time.sleep(1)

您可以使用multiprocessing模塊在兩個模塊之間實現Pipe 然后,您可以將其中一個模塊作為進程啟動,並使用管道與其進行通信。 使用管道的最佳部分是您還可以通過它傳遞諸如 dict、list 之類的 Python 對象。

例如:mp2.py:

from multiprocessing import Process,Queue,Pipe
from mp1 import f

if __name__ == '__main__':
    parent_conn,child_conn = Pipe()
    p = Process(target=f, args=(child_conn,))
    p.start()
    print(parent_conn.recv())   # prints "Hello"

mp1.py:

from multiprocessing import Process,Pipe

def f(child_conn):
    msg = "Hello"
    child_conn.send(msg)
    child_conn.close()

如果您想在 2 個單獨運行的腳本之間讀取和修改共享數據,一個好的解決方案是,利用 python 多處理模塊,並使用Pipe() 或 Queue() (請參閱此處的差異)。 這樣,您就可以同步腳本,並避免有關並發性和全局變量的問題(例如,如果兩個腳本都想同時修改變量會發生什么情況)。

正如 Akshay Apte 在他的回答中所說,使用管道/隊列的最佳部分是您可以通過它們傳遞 python 對象。

此外,如果還沒有任何數據通過( queue.empty()pipeConn.poll() ),還有一些方法可以避免等待數據。

請參閱下面使用 Queue() 的示例:

    # main.py
    from multiprocessing import Process, Queue
    from stage1 import Stage1
    from stage2 import Stage2


    s1= Stage1()
    s2= Stage2()

    # S1 to S2 communication
    queueS1 = Queue()  # s1.stage1() writes to queueS1

    # S2 to S1 communication
    queueS2 = Queue()  # s2.stage2() writes to queueS2

    # start s2 as another process
    s2 = Process(target=s2.stage2, args=(queueS1, queueS2))
    s2.daemon = True
    s2.start()     # Launch the stage2 process

    s1.stage1(queueS1, queueS2) # start sending stuff from s1 to s2 
    s2.join() # wait till s2 daemon finishes
    # stage1.py
    import time
    import random

    class Stage1:

      def stage1(self, queueS1, queueS2):
        print("stage1")
        lala = []
        lis = [1, 2, 3, 4, 5]
        for i in range(len(lis)):
          # to avoid unnecessary waiting
          if not queueS2.empty():
            msg = queueS2.get()    # get msg from s2
            print("! ! ! stage1 RECEIVED from s2:", msg)
            lala = [6, 7, 8] # now that a msg was received, further msgs will be different
          time.sleep(1) # work
          random.shuffle(lis)
          queueS1.put(lis + lala)             
        queueS1.put('s1 is DONE')
    # stage2.py
    import time

    class Stage2:

      def stage2(self, queueS1, queueS2):
        print("stage2")
        while True:
            msg = queueS1.get()    # wait till there is a msg from s1
            print("- - - stage2 RECEIVED from s1:", msg)
            if msg == 's1 is DONE ':
                break # ends loop
            time.sleep(1) # work
            queueS2.put("update lists")             

編輯:剛剛發現您可以使用queue.get(False)來避免接收數據時的阻塞。 這樣就不需要先檢查隊列是否為空。 如果您使用管道,這是不可能的。

您可以使用pickling 模塊在兩個python 程序之間傳遞數據。

import pickle 

def storeData(): 
    # initializing data to be stored in db 
    employee1 = {'key' : 'Engineer', 'name' : 'Harrison', 
    'age' : 21, 'pay' : 40000} 
    employee2 = {'key' : 'LeadDeveloper', 'name' : 'Jack', 
    'age' : 50, 'pay' : 50000} 

    # database 
    db = {} 
    db['employee1'] = employee1 
    db['employee2'] = employee2 

    # Its important to use binary mode 
    dbfile = open('examplePickle', 'ab') 

    # source, destination 
    pickle.dump(db, dbfile)                   
    dbfile.close() 

def loadData(): 
    # for reading also binary mode is important 
    dbfile = open('examplePickle', 'rb')      
    db = pickle.load(dbfile) 
    for keys in db: 
        print(keys, '=>', db[keys]) 
    dbfile.close() 

這將使用 TCP 主機套接字將數據傳入和傳出兩個正在運行的腳本。 https://zeromq.org/languages/python/ 所需模塊 zmq:使用( pip 安裝 zmq )。 這稱為客戶端服務器通信。 服務器將等待客戶端發送請求。 如果服務器沒有運行,客戶端也不會運行。 此外,這種客戶端服務器通信允許您從一個設備(客戶端)向另一設備(服務器)發送請求,只要客戶端和服務器在同一網絡上並且您更改 localhost(服務器的 localhost 標記為with: * )to the actual IP of your device(server)( IP help( go into your device network settings, click on your network icon, find advanced or properties, look for IP address. note this may be different from going to google並詢問您的 ip。我使用的是 IPV6 所以。DDOS 保護。))將客戶端的本地主機 IP 更改為服務器 IP。 對OP的問題。 您是否必須讓腳本 b 始終運行,或者可以將腳本 b 作為模塊導入到腳本 a 中? 如果是這樣,請查看如何制作 python 模塊。

我使用 lib Shared Memory Dict解決了同樣的問題,它是multiprocessing.shared_memory的一個非常簡單的 dict 實現。

源代碼1.py

from shared_memory_dict import SharedMemoryDict
from time import sleep

smd_config = SharedMemoryDict(name='config', size=1024)

if __name__ == "__main__":
    smd_config["status"] = True

    while True:
        smd_config["status"] = not smd_config["status"]
        sleep(1)

源代碼2.py

from shared_memory_dict import SharedMemoryDict
from time import sleep

smd_config = SharedMemoryDict(name='config', size=1024)

if __name__ == "__main__":
    while True:
        print(smd_config["status"])
        sleep(1)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM