Python3 多处理一个“for”循环

Posted

技术标签:

【中文标题】Python3 多处理一个“for”循环【英文标题】:Python3 multiprocessing a 'for' loop 【发布时间】:2018-07-18 02:56:02 【问题描述】:

我真的很想问这个问题,因为即使我阅读了文档并看到了一些示例,也无法真正理解如何使用它。

我有一个 Raspberry pi 3 型号 B,我交叉编译了 QT 5.6 和最新的 SIP 和 PyQt5 版本来开发 Python GUI 并使用 linux 帧缓冲区,一切都很成功,直到我运行了这部分代码

def refresh_data(self):
        if self.setTarget == 1:
            for x in range(0, self.targetnum):
                self.target.append(getShadowInfo(x))
                if float(self.target[x]) != self.datalist[x]:
                    if float(self.target[x]) > self.datalist[x]:
                        self.step.append(float(self.target[x]) - self.datalist[x])
                        self.negative.append(0)
                    else:
                        self.step.append(self.datalist[x] - float(self.target[x]))
                        self.negative.append(1)
                else:
                    self.step.append(0)
                    self.negative.append(0)
                self.step[x] *= 0.1
            self.setTarget = 0
            self.setTodaysDate(self.year, self.month, self.day, self.hour, self.min)
        self.stopv += 10
        for x in range(0, self.targetnum):
            if self.step[x] != 0:
                if self.negative[x] == 0:
                    self.datalist[x] += self.step[x]
                else:
                    self.datalist[x] -= self.step[x]
                self.setCustomParameter(x)
        if all(i == 0 for i in self.step):
            self.timer.stop()
        if self.stopv >= 100:
            self.timer.stop()

它从外部文件中读取数据并将其设置为目标,然后增加或减少实际值以在 python GUI 上更新它,这样看起来很流畅,但同时发生这种情况,性能变差并且它甚至执行代码的速度比应有的速度慢(由 50ms Qtimer 运行)。使用 htop,我注意到在运行这部分代码时,我的 RPi 只使用了四个内核中的一个,有人可以帮我多处理两个 for 循环吗?或者更好的 refresh_data 函数?

编辑!

setCustomParameter 函数

def setCustomParameter(self, intparameter):
        if intparameter == 1:
            #RPMMeter
            self.hygrometer.setProperty("gaugeValue", round(self.datalist[1], 2))
            self.label_5.setText(QCoreApplication.translate("MainWindow", "Engine Speed: " +
            str(round(self.datalist[1], 2)) + " RPM"))
        if intparameter == 2:
            #Pressure
            self.label.setText(QCoreApplication.translate("MainWindow",
            str(round(self.datalist[2], 2)) + " KPa"))
            self.progressBar.setProperty("value", self.datalist[2])
        if intparameter == 3:
            self.thermometer.setProperty("thermoValue", round(self.datalist[3], 2))
        if intparameter == 4:
            self.KW_Meter.setProperty("gaugeValue", round(self.datalist[4], 2))
        if intparameter == 5:
            self.Battery_bank_label.setText(QCoreApplication.translate("MainWindow",
            "Battery Bank Voltage: " + str(round(self.datalist[5], 2)) + "V (MEDIUM)"))

【问题讨论】:

您能否将您的问题简化为对问题至关重要的点? 两个for循环,第一个,从另一个文件中读取信息并与实际信息进行比较,然后存储目标,第二个,设置目标增加或减少10%,我的树莓这样做变慢了,如果可能的话,如何多处理这两个 for 循环,如何多处理函数“refresh_data” 我实际上是在谈论问题本身。你可以编辑它。这里的许多人都是非常忙碌的专家,他们正在投入私人时间,最好将他们必须做的阅读量减少到最低限度。顺便说一句,这是您可以在 How to ask 部分找到的提示之一。 知道了,已经编辑了,我删除了所有无用的背景说明 【参考方案1】:

通过巧妙地放置 if 语句,您可以通过将(两个 for 循环,1 个 all 也是一个 for 循环)减少到 1 个 for 循环来将速度提高 3 倍。

通过压缩目标数据列表。假设 self.target、self.negative、self.datalist 和 self.step 的长度都相同。

for i, (t, d) in enumerate(zip(self.target, self.datalist)):
    t = float(t)
    if (t != d) and (t > d) and (self.setTarget == 1):
        self.target.append(getShadowInfo(x))
        self.datalist = d + (t - d) * .1
    elif (t != d) and (t <= d) and (self.setTarget == 1):
        self.target.append(getShadowInfo(x))
        self.datalist = d - (d - t) * .1
    else:
        self.setCustomParameter(i)

if self.setTarget == 1
    self.setTarget = 0
    self.setTodaysDate(self.year, self.month, self.day, self.hour, self.min)

如果您能够弄清楚如何将 for 循环减少到 1 个,那么您可以通过从 multiprocessing.pool.Pool 返回索引和数据来完全替换 for 循环来对它进行多重处理:

# replacing ... self.datalist = d - (d - t) * .1
# with ... return i, d - (d - t) * .1
results = mp.Pool(4).starmap(return_data, zip(self.target, self.datalist))
for i, d in results:
    self.datalist[i] = d

注意:诀窍在于弄清楚如何在不改变 for 循环中的 self.target 的情况下处理需要更新的内容

【讨论】:

对不起,我觉得我太初学者了,看不懂你的答案(不知道 t 和 d 的作用),脚本有效,我可以看到 GUI,但是当我按下 Refresh 时什么都不做,首先,因为函数setCustomParameter是on else,如果不满足条件,我把它放在里面但它仍然没有更新参数,我要编辑问题以添加函数。另外,我认为您不应该压缩目标和数据列表,目标最初是一个空列表,通过附加变量“targetnum”(即数据列表长度)来填充它,我仍然觉得您的回答非常有用。跨度> 到目前为止,我得到了这个工作:pastebin.com/rYwx8VwA 但是,它只更新一次,然后,不跟上,不知道为什么,我很确定Qtimer 设置正确 对于任何想知道的人来说,多亏了这个答案,我改进了很多 python 脚本并学到了一些东西,但是,python 脚本甚至不会太大而无法减慢 RPi,问题不在于代码,而在于屏幕分辨率,显然这很重要,我使用的是高清电视(1080p),FPS 在 20-25 左右,与 GUI 交互时下降到 2-7 FPS,我设置了raspi-config 上的屏幕分辨率为 480p,我一直得到 60 FPS,与 UI 交互时仅下降到 57 或 55

以上是关于Python3 多处理一个“for”循环的主要内容,如果未能解决你的问题,请参考以下文章

多处理一个for循环?

使用多处理并发执行一个 for 循环

for循环内的多处理

For循环上的Python多处理

为啥我使用多处理/多线程的函数在 for 循环中使用时如此缓慢,但在循环之外却没有?

在将结果附加到字典的 for 循环上使用 python 多处理