当前,我正在尝试在Python程序中产生一个进程,该程序再次创建线程,这些线程在进程地址空间中连续更新变量。到目前为止,我想出了可以运行的代码,但是变量的更新似乎没有传播到进程级别。我曾希望在进程地址空间中定义一个变量并在线程(共享进程的地址空间)中使用global,将允许线程操纵变量并将更改传播到进程。
以下是该问题的一个最小示例:
import multiprocessing
import threading
import time
import random
def process1():
lst = {}
url = "url"
thrd = threading.Thread(target = urlCaller, args = (url,))
print("process alive")
thrd.start()
while True:
# the process does some CPU intense calculation
print(lst)
time.sleep(2)
def urlCaller(url):
global lst
while True:
# the thread continuously pulls data from an API
# this is I/O heavy and therefore done by a thread
lst = {random.randint(1,9), random.randint(20,30)}
print(lst)
time.sleep(2)
prcss = multiprocessing.Process(target = process1)
prcss.start()
当线程按预期方式打印包含两个整数的列表时,该过程始终会打印一个空列表。我希望该过程也可以打印出两个整数的列表。 (注意:我将Spyder用作IDE,并且如果我在Linux / Ubuntu上运行此代码,则以某种方式仅将某些内容打印到控制台,但是如果我在Windows上的Spyder中运行完全相同的代码,则不会打印任何内容到控制台。)>
我知道使用全局变量并不总是一个好的解决方案,但我认为在这种情况下,可以很好地达到目的。
您可能想知道为什么我要在进程中创建线程。基本上,我需要对不断变化的不同数据集执行相同的复杂计算。因此,我需要多个进程(每个数据集一个)来优化我的CPU利用率,并在进程中使用线程以使I / O进程最高效。数据的折旧速度非常快,因此,我不能仅将其存储在数据库或文件中,这当然可以简化数据生产者(线程)和数据使用者(过程)之间的通信过程。
答案 0 :(得分:1)
您正在函数lst
内定义局部变量 process1
,因此urlCaller
的操作无关紧要,它无法更改其他变量的局部变量功能。 urlCaller
定义了一个全局变量,但是process1
永远看不到它,因为它被您定义的局部变量所遮盖。
您需要从该函数中删除lst = {}
,并找到另一种方法来返回值或在其中声明变量global
:
def process1():
global lst
lst = {}
url = "url"
thrd = threading.Thread(target = urlCaller, args = (url,))
print("process alive")
thrd.start()
while True:
# the process does some CPU intense calculation
print(lst)
time.sleep(2)
我会使用类似concurrent.futures
之类的东西,而不是直接使用threading
模块。
答案 1 :(得分:0)
由于前面的回答,我发现最好实现一个流程类并在该类中定义“线程功能”。现在,线程可以访问共享变量并操纵该变量,而无需使用“ thread.join()”并终止线程。
下面是一个最小的示例,其中2个并发线程为父进程提供数据。
import multiprocessing
import threading
import time
import random
class process1(multiprocessing.Process):
lst = {}
url = "url"
def __init__(self, url):
super(process1, self).__init__()
self.url = url
def urlCallerInt(self, url):
while True:
self.lst = {random.randint(1,9), random.randint(20,30)}
time.sleep(2)
def urlCallerABC(self, url):
while True:
self.lst = {"Ab", "cD"}
time.sleep(5)
def run(self):
t1 = threading.Thread(target = self.urlCallerInt, args=(self.url,))
t2 = threading.Thread(target = self.urlCallerABC, args=(self.url,))
t1.start()
t2.start()
while True:
print(self.lst)
time.sleep(1)
p1 = process1("url")
p1.start()