How to run a Python script without locking Blender?
For a process like baking a number of frequencies from an audio file, I use the modal timer operator.  Eg If I have a long audio file and it takes 5mins to bake one frequency out of a set of 16, I bake one then have a small wait time to allow the handler to catch an escape key which throws up a  menu to cancel (and clean up)  or continue, rather than have to wait 16x5 or kill blender.  It doesn't however let me cancel amid a bake.

For convenience I have used the BakeSoundPanel Panel class to store data on the status of the bake. 



class SD_ContinueBakeOperator(Operator):
    """Continue Baking"""
    bl_idname = "sounddrivers.continue_baking"
    bl_label = "Continue"


    def execute(self, context):
        BakeSoundPanel.wait = 2
        BakeSoundPanel.cancel_baking = False
        return {'FINISHED'}

class SD_CancelBakeOperator(Operator):
    """Cancel Baking"""
    bl_idname = "sounddrivers.cancel_baking"
    bl_label = "Cancel"


    def execute(self, context):
        BakeSoundPanel.cancel_baking = True
        return {'FINISHED'}

class ModalTimerOperator(bpy.types.Operator):
    """Operator which runs its self from a timer"""
    bl_idname = "wm.modal_timer_operator"
    bl_label = "Modal Timer Operator"

    _timer = None

    def modal(self, context, event):

        def confirm_cancel(self, context):
            layout = self.layout
            layout.operator("sounddrivers.cancel_baking")
            layout.operator("sounddrivers.continue_baking")

        if BakeSoundPanel.cancel_baking:
            self.clean()
            return self.cancel(context)

        if event.type == 'ESC' or not BakeSoundPanel.baking:
            context.window_manager.popup_menu(confirm_cancel, title="Baking", icon='SOUND')
            BakeSoundPanel.wait = 1000000
            return {'PASS_THROUGH'}
            self.clean()
            return self.cancel(context)

        if BakeSoundPanel.wait &gt; 0:
            BakeSoundPanel.wait -= 1
            return {'PASS_THROUGH'}

        if event.type == 'TIMER':
            BakeSoundPanel.baking = True
            # bake a sound, when finished set self.wait to some "wait time"
            # to enable a cancel

        return {'PASS_THROUGH'}