There are three main scenarios:
1. IPRoute without caching — just a plain socket object, suitable to be used in poll/select loops. It provides also high-level netlink API, so it is possible to register the socket in the main poll() loop and then call IPRoute.get() to get the next broadcast message.
2. IPRoute with caching — can not be used with poll/select. May be used in exclusive endless loops, since IPRoute.get() is a blocking call.
3. IPDB, which has it's own main loop, but provides callback registration via IPDB.register_callback(), see also [1] and [2]. There are pre- and post-callbacks, former are blocking and run in the loop thread before own IPDB callbacks and latter are async and run in separate threads.