Reputation: 17
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()
I have done a lot of surfing for the solution to this and none of the applications I have found work when applied to my situation. The BAC0.device() callout is what my code is constantly waiting for. What I have now does not move onto the next device callout until the previous one has returned and this is significantly slowing performance.
What I need to do is create those devices asynchronously so that it is not constantly waiting for the previous one to connect before making the next one. Thanks for any advice/help!
Upvotes: 0
Views: 605
Reputation: 839
Worth noting that every call to a BAC0.device
depends on a thread that bacpypes
(the module that handle BACnet communication) creates when we create the bacnet network. And this thread makes all the network calls to be executed one after the other.
Bacpypes (because of the way BACnet works) will keep the socket open as long as it runs so you will not be able to launch multiple bacnet instances running at the same time... you would need more than one NIC (or any other trick that would allow opening a new socket) to be able to make that asynchronous.
If you want to gain speed, I think you would have better results defining all the devices globally, and use custom object lists to reduce the number of points.
Once defined, all the devices will get updated in the background. You can then use the
dev[“MyPoint”].lastValue
Trick to force your soft to use the last polled value (instead of forcing a new read on the network)
If you really want to use async and await for BACnet communication, you would probably need to start with bacpypes itself. I know that Joel is thinking about a way to make the module asynchronous but it’s still far away. But BAC0 being nothing more than a “wrapper” around bacpypes, it is really “synchronous”.
If BAC0 is to be used inside an asynchronous app, I think there are some “ways” to handle synchronous stuff but here ends my knowledge about async and await.
By the way, if you make some progress with it, don’t hesitate to drop by Github and leave something ! I’m really interested in knowing what is done with BAC0.
Upvotes: 1
Reputation: 3461
Right now, your load_devices
is asynchronous, but you're waiting for each call to it to finish before starting the next one.
I'd replace your final for
loop with this.
tasks = [load_devices(device) for device in deviceNames]
await asyncio.gather(*tasks)
This makes an awaitable for each call, then awaits them all at once, rather than awaiting each individually.
(Note: the tasks
list technically contains coroutines, not Task
objects, because asyncio.gather
does all the Task
-creation automatically. You can run asyncio.create_task
on each one if you really want to, but it won't change the outcome.)
EDIT: It sounds like you want to do this in a non-async function. In that case:
tasks = [load_devices(device) for device in deviceNames]
devices = loop.run_until_complete(asyncio.gather(*tasks))
Upvotes: 0