【问题标题】:Passing data between separately running Python scripts在单独运行的 Python 脚本之间传递数据
【发布时间】:2017-10-07 06:05:44
【问题描述】:

如果我正在运行一个 python 脚本(带有完整的 Tkinter GUI 和所有内容)并且我想将它收集的实时数据(内部存储在数组等中)传递给另一个 python 脚本,那么最好的方法是什么那个?

我不能简单地将脚本 A 导入脚本 B,因为它将创建脚本 A 的新实例,而不是访问已经运行的脚本 A 中的任何变量。

我能想到的唯一方法是让脚本 A 写入文件,然后脚本 B 从文件中获取数据。但是,这不太理想,因为如果脚本 B 尝试读取脚本 A 已经写入的文件,则可能会发生一些不好的事情。另外,我正在寻找两个程序之间更快的通信速度。

编辑: 以下是所要求的示例。我知道为什么这不起作用,但这是需要实现的基本前提。我的源代码很长而且很不幸是保密的,所以在这里没有帮助。总之,脚本 A 运行 Tkinter 并收集数据,而脚本 B 是 views.py 作为 Django 的一部分,但我希望这可以作为 Python 的一部分来实现。

脚本 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)

【问题讨论】:

  • 您应该能够将一个模块导入另一个模块,实例化单个实例(必要时使用单例),然后为该实例分配属性/值,以便您可以根据需要从中读取辅助脚本。
  • 如果脚本不是太长或太敏感,查看源代码会有所帮助
  • 也许你可以使用文件套接字?这似乎是流数据的一种选择。
  • 问题含糊不清。 “将实时数据传递给另一个脚本”可能意味着许多不同的事情。你怎么通过它?通过插座?通过一个宁静的界面?作为命令行参数?您是在启动第二个程序时传递一次数据,还是随着数据的变化不断更新数据?请出示Minimal, Complete, and Verifiable example

标签: python python-2.7 tkinter


【解决方案1】:

这将使用 TCP 主机套接字将数据传入和传出两个正在运行的脚本。 https://zeromq.org/languages/python/。所需模块 zmq:使用(pip install zmq)。 这称为客户端服务器通信。服务器将等待客户端发送请求。如果服务器没有运行,客户端也不会运行。此外,这种客户端服务器通信允许您从一个设备(客户端)向另一设备(服务器)发送请求,只要客户端和服务器在同一网络上并且您更改 localhost(服务器的 localhost 标记为与:*)到您的设备(服务器)的实际 IP(IP 帮助(进入您的设备网络设置,单击您的网络图标,找到高级或属性,查找 IP 地址。注意这可能与去谷歌不同并询问您的 IP。我正在使用 IPV6。DDOS 保护。))将客户端的 localhost IP 更改为服务器 IP。对OP的问题。您是否必须让脚本 b 始终运行,或者可以将脚本 b 作为模块导入到脚本 a 中?如果是这样,请查看如何制作 python 模块。

【讨论】:

    【解决方案2】:

    如果您想读取和修改共享数据,在两个单独运行的脚本之间,一个好的解决方案是利用 python 多处理模块,并使用Pipe() or a Queue()(参见差异@ 987654322@)。这样,您可以同步脚本,并避免有关并发和全局变量的问题(例如如果两个脚本都想同时修改一个变量会发生什么)。

    正如 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)来避免接收数据时的阻塞。这样就不需要先检查队列是否为空。如果你使用管道,这是不可能的。

    【讨论】:

      【解决方案3】:

      您可以使用 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() 
      

      【讨论】:

        【解决方案4】:

        您可以使用multiprocessing 模块在两个模块之间实现Pipe。然后,您可以将其中一个模块作为进程启动并使用管道与其通信。使用管道最好的部分是您还可以通过它传递 python 对象,如 dict,list。

        例如: 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()
        

        【讨论】:

        • 这似乎是要走的路,但是为什么以下不起作用?如果把这段代码加到mp1.py的末尾:i = 0 def g(): print i if __name__ == "__main__": while True: i = i + 1 g() 为什么运行mp2.py没有返回当前的i?
        • 不太明白你的问题。但是如果你想调用函数g(),你需要在p = Process(target=g, args=(child_conn,))中指定它
        • 查看编辑中的示例,如果您将代码插入其中,mp2 将返回 0 而不是 mp1 中的 i。
        猜你喜欢
        • 2011-01-19
        • 2023-04-10
        • 1970-01-01
        • 2021-06-01
        • 2018-01-07
        • 1970-01-01
        • 2020-03-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多