Repetition number 849 (well, actually number print(int(1000*random.random())))...
The most important differentiation in this context is between modal and modeless.
Please be aware that the Revit API is single-threaded and only runs within a valid Revit API context, Such a context is only provided by Revit in one of the numerous event handlers defined by the API and runs in the main thread of Revit. This blocks the UI, just as you say.
You can avoid this by executing parts of your add-in in a separate modeless thread. The modeless part can release the main thread, allow Revit to continue doing other stuff, and both Revit and the add-in can continue interacting with the user. However, this modeless part of your add-in has no access to the Revit API.
The preferred (and almost only) way for the modeless part of your add-in to interact with the Revit API and gain access to a valid Revit API context enabling it to do so is to implement an external event. The external event can be raised from the modeless part of the add-in. Revit then calls the corresponding event handler and provides it with a valid Revit API context.
This is discussed in great depth and with many examples by The Building Coder, and in nuerous other posts here in the forum: