Использование asyncio для циклического перемещения по списку и выполнения вызовов, не дожидаясь повторной обработки предыдущего вызова. - PullRequest
0 голосов
/ 23 января 2019
async def load_devices(deviceName):
    deviceIP = deviceName[1]
    deviceNumber = deviceName[2]
    device = BAC0.device(deviceIP, deviceNumber, bacnet, poll=trends_every)
    return device  

def get_attributes(self):
    self.get_attribute_button.destroy()

    deviceNames = list(bacnet.devices.values.tolist())

    loop = asyncio.get_event_loop()

    global devices

    for device in deviceNames:
        devices = loop.run_until_complete(asyncio.gather(load_devices(device)))
    loop.close()

Я много занимался серфингом для решения этой проблемы, и ни одно из приложений, которые я нашел, не работало применительно к моей ситуации.Мой код постоянно ожидает BAC0.device ().То, что у меня есть, не переходит к следующему вызову устройства, пока не вернется предыдущее, и это значительно снижает производительность.

Что мне нужно сделать, это создать эти устройства асинхронно, чтобы не было постоянного ожидания подключения предыдущего устройства перед созданием следующего.Спасибо за любой совет / помощь!

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

Стоит отметить, что каждый вызов BAC0.device зависит от потока, который bacpypes (модуль, который управляет связью BACnet) создает при создании сети BACNET. И этот поток заставляет все сетевые вызовы выполняться один за другим.

Bacpypes (из-за того, как работает BACnet) будет держать сокет открытым до тех пор, пока он работает, поэтому вы не сможете запускать несколько экземпляров bacnet, работающих одновременно ... вам потребуется более одного сетевого адаптера (или любой другой трюк, который позволил бы открыть новый сокет), чтобы сделать это асинхронным.

Если вы хотите набрать скорость, я думаю, что вы получите лучшие результаты, определяя все устройства в глобальном масштабе, и используйте собственные списки объектов, чтобы уменьшить количество точек.

После определения все устройства будут обновляться в фоновом режиме. Затем вы можете использовать

dev[“MyPoint”].lastValue

Хитрость, заставляющая ваш софт использовать последнее значение опроса (вместо принудительного нового чтения в сети)

Если вы действительно хотите использовать асинхронное соединение и ожидать подключения к BACnet, вам, вероятно, следует начать с самого bacpypes. Я знаю, что Джоэл думает о том, как сделать модуль асинхронным, но он еще далеко. Но BAC0 является не более чем «оболочкой» вокруг bacpypes, он действительно «синхронный».

Если BAC0 будет использоваться внутри асинхронного приложения, я думаю, что есть несколько «способов» работать с синхронными вещами, но на этом мои знания об асинхронности и ожидании заканчиваются.

Кстати, если вы добьетесь некоторого прогресса в этом, не стесняйтесь заглянуть в Github и оставить что-нибудь! Мне действительно интересно узнать, что делается с BAC0.

0 голосов
/ 23 января 2019

Сейчас ваш load_devices асинхронный, но вы ожидаете завершения каждого вызова, прежде чем начинать следующий.

Я бы заменил ваш последний цикл for на это.

tasks = [load_devices(device) for device in deviceNames]
await asyncio.gather(*tasks)

Это делает ожидание для каждого вызова, а затем ожидает их всех сразу, а не ожидание каждого по отдельности.

(Примечание: список tasks технически содержит сопрограммы , а не Task объекты, потому что asyncio.gather выполняет все Task создание автоматически. Вы можете запустить asyncio.create_task для каждого из них если вы действительно хотите, но это не изменит результат.)

РЕДАКТИРОВАТЬ: Похоже, вы хотите сделать это в не асинхронной функции. В этом случае:

tasks = [load_devices(device) for device in deviceNames]
devices = loop.run_until_complete(asyncio.gather(*tasks))
...