cantools大量解析报文的效率问题

img


大家可以一起探讨。
确实遇到瓶颈,无从下手了。
希望可以找到最优解。

大家不要使用 chatGPT回答 ,chatgpt的方式都已经测试过,无法支持这样的库,或者效率没有提升。

我的想法用python获取数据,C来解析数据,解析出来存为csv格式,不要存datafram。少用Python,因为python是出了名的慢,GIL限制了性能


>>> import cantools
>>> from pprint import pprint
>>> db = cantools.database.load_file('tests/files/dbc/motohawk.dbc')
>>> db.messages
[message('ExampleMessage', 0x1f0, False, 8, 'Example message used as template in MotoHawk models.')]
>>> example_message = db.get_message_by_name('ExampleMessage')
>>> pprint(example_message.signals)
[signal('Enable', 7, 1, 'big_endian', False, 1.0, 0, 0.0, 0.0, '-', False, None, {0: 'Disabled', 1: 'Enabled'}, None),
 signal('AverageRadius', 6, 6, 'big_endian', False, 0.1, 0, 0.0, 5.0, 'm', False, None, None, ''),
 signal('Temperature', 0, 12, 'big_endian', True, 0.01, 250, 229.53, 270.47, 'degK', False, None, None, None)]

  • 以下回答由chatgpt基于相关博客总结生成:

    感知机是一种简单的神经网络模型,它能够对输入数据进行二分类。具体来说,给定输入向量$x$和权重向量$w$,感知机的输出为$y=sign(w\cdot x+b)$,其中$w\cdot x$表示$w$和$x$的点积,$b$表示偏置项,$sign$是激活函数,可以是符号函数或者阶跃函数等。

    如果要使用感知机对某个具体的数据进行分类,需要先进行训练,即调整权重和偏置项,使得感知机能够对已知的训练集进行正确的分类。训练的过程可以使用随机梯度下降等方法。

    具体到上述参考资料中的Python实现,可以按照以下步骤进行:

    1. 定义激活函数

    感知机的激活函数可以是符号函数或者阶跃函数等,这里定义一个符号函数:

    def sign(x):
        if x >= 0:
            return 1
        else:
            return -1
    
    1. 定义感知机模型

    感知机的模型可以通过定义一个类来完成。

    首先,在初始化函数中定义模型的输入参数个数和激活函数,并初始化权重向量和偏置项:

    class Perceptron(object):
        def __init__(self, input_num, activator):
            self.activator = activator
            self.weights = [0.0 for _ in range(input_num)]
            self.bias = 0.0
    

    然后,定义模型的输出函数和训练函数:

        def predict(self, input_vec):
            output = np.dot(input_vec, self.weights) + self.bias
            return self.activator(output)
    
        def train(self, input_vecs, labels, iteration, rate):
            for i in range(iteration):
                self._one_iteration(input_vecs, labels, rate)
    
        def _one_iteration(self, input_vecs, labels, rate):
            samples = zip(input_vecs, labels)
            for (input_vec, label) in samples:
                output = self.predict(input_vec)
                self._update_weights(input_vec, output, label, rate)
    
        def _update_weights(self, input_vec, output, label, rate):
            delta = label - output
            self.weights = list(map(
                lambda x_w: x_w[1] + rate * delta * x_w[0], 
                zip(input_vec, self.weights)))
            self.bias += rate * delta
    

    其中,predict函数接收输入向量,计算模型输出;train函数接收训练输入和标签数据,以及训练轮数和学习速率,使用_one_iteration函数进行训练;_one_iteration函数一次迭代更新所有训练样本的权重和偏置项;_update_weights函数按照感知机规则更新权重和偏置项。

    1. 使用训练数据进行训练

    给定训练数据集,调用train函数进行训练:

    input_vecs = [[1, 1], [0, 0], [1, 0], [0, 1]]
    labels = [1, 0, 0, 0]
    p = Perceptron(2, sign)
    p.train(input_vecs, labels, 10, 0.1)
    

    其中,input_vecs是训练输入向量列表,labels是训练标签列表,10是训练轮数,0.1是学习速率。

    1. 使用训练好的模型进行预测

    训练好模型后,可以使用predict函数进行分类预测:

    p.predict([1, 1]) #返回1
    p.predict([0, 0]) #返回-1
    p.predict([1, 0]) #返回-1
    p.predict([0, 1]) #返回-1
    

    其中,输入向量的分别对应四种逻辑"and"的输入,输出分别表示模型对应的分类结果。

以下内容由CHATGPT及阿里嘎多学长共同生成、有用望采纳:

对于cantools大量解析报文的效率问题,可以考虑以下几个方面来优化:

  1. 使用multiprocessing库进行多进程处理,将大量报文分配到不同的进程中处理,提高解析效率。

  2. 对解析过程进行优化,例如使用字典代替列表,减少查找时间;使用生成器代替列表生成式,减少内存占用等。

  3. 对于重复解析的报文,可以使用缓存技术将解析结果缓存下来,避免重复解析,提高效率。

  4. 如果解析的报文格式固定,可以考虑使用C语言等高效语言编写解析程序,然后通过Python调用,提高解析速度。

下面是一个使用multiprocessing库进行多进程处理的例子:

import cantools
import multiprocessing

def parse_can(file_name, msg_id):
    db = cantools.database.load_file(file_name + '.dbc')
    msg = db.get_message_by_name(msg_id)
    # 解析报文
    ...

if __name__ == '__main__':
    file_name = 'test'
    msg_id_list = ['can_msg1', 'can_msg2', 'can_msg3']
    pool = multiprocessing.Pool(processes=multiprocessing.cpu_count())
    for msg_id in msg_id_list:
        pool.apply_async(parse_can, (file_name, msg_id))
    pool.close()
    pool.join()

在上面的例子中,我们使用了multiprocessing.Pool创建了多个进程来处理不同的报文,从而提高了解析效率。

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
cantools 作为一个开源的工具库,本身已经针对性能做了一些优化,例如使用 Cython 实现了部分解析功能以提高速度。但在处理大量报文时仍会出现性能瓶颈。优化的方式主要包括以下几种:

1.采用字典缓存解析结果:在解析、编码报文时,可以将解析结果以字典形式缓存,避免重复解析带来的性能损耗。在后续解析过程中,可以直接从字典中获取之前解析的结果,而无需重新解析。

2.使用多进程或多线程并行解析:可以将报文分成多个子集,分别交给不同的进程或线程解析,提高解析速度。需要注意的是,多进程开销较大,适用于解析大量数据;而多线程则更适合解析大规模数据。

3.减少解析方法的调用:在解析过程中,可以尽可能减少解析方法的调用次数,避免函数调用栈过深带来的性能损耗。例如,在遍历报文时,可以尽可能多的使用索引访问,而不是调用解析方法获取值。

下面是一个使用字典缓存和多线程并行的示例代码(仅供参考):

import cantools
import threading

can_db = cantools.db.load_file('can.dbc')
msg_list = [...] # 待解析的报文列表

# 定义解析结果缓存字典
cache = {}

# 定义解析线程类
class ParseThread(threading.Thread):
    
    def __init__(self, msgs):
        super().__init__()
        self.msgs = msgs
    
    def run(self):
        for msg in self.msgs:
            if str(msg.arbitration_id) in cache:
                # 从缓存中获取解析结果
                result = cache[str(msg.arbitration_id)]
            else:
                # 解析报文并缓存结果
                result = can_db.decode_message(msg.arbitration_id, msg.data)
                cache[str(msg.arbitration_id)] = result

# 将报文列表分成多个子集
n_thread = 4
step = len(msg_list) // n_thread
sublists = [msg_list[i:i+step] for i in range(0, len(msg_list), step)]

# 开启多个解析线程
threads = [ParseThread(sublist) for sublist in sublists]
for thread in threads:
    thread.start()

# 等待所有线程结束
for thread in threads:
    thread.join()

# 输出解析结果
for msg in msg_list:
    result = cache[str(msg.arbitration_id)]
    # do something with result...

如果我的回答解决了您的问题,请采纳!