创建一个进程,该进程创建一个线程,该线程将再次更新全局变量



目前,我正在尝试在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/Ubuuntu上运行此代码,则只会将某些内容打印到控制台,但如果我在Windows上的Spyder中运行完全相同的代码,则不会将任何内容打印到控制台。(

我知道全局变量的使用并不总是一个好的解决方案,但我认为在这种情况下,它很好地达到了目的。

您可能想知道我为什么要在进程中创建线程。基本上,我需要在不断变化的不同数据集上运行相同的复杂计算。因此,我需要多个进程(每个数据集一个(来优化CPU的利用率,并使用进程中的线程来提高I/O进程的效率。数据贬值非常快,因此,我不能只将其存储在数据库或文件中,这当然会简化数据生产者(线程(和数据消费者(进程(之间的通信过程。

您在函数process1内定义了一个局部变量lst,因此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模块。

感谢前面的回答,我发现最好在这个类中实现一个进程类并定义"线程函数"。现在,线程可以访问共享变量并操作该变量,而无需使用"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()

最新更新