I'll try to explain it in layman terms, hopefully it is not very far from the actual technical workings of a render engine. If someone with true programming inside knowledge wants to barge in, please do correct me if I'm wrong
While rendering Blender, and most other rendering software for that matter, divides your image up into small digestible chunks, like buckets samples, or whatever method is more adequate for the current render engine.
These chunks are then run through some sort of scheduling agent that queues them and sends them to the available processing units, be it a GPU, CPU core, one of several networked computers, a Farm or whatever.
The scheduler then waits for the processing units to churn through that data, produce the image slice and return them as rendered raster information chunks to send in a new one afterwards.
Until that chunk is returned Blender has little or no control over that processing unit, all it can do is wait for the returned information.
If you cancel a render most of the time the only way to actually stop it is by not sending a new chunk, and even if a "cancel" signal can be sent, often the processing unit is busy and can't act on it immediately or at least until it finishes that current job anyway.
The time until the signal is interpreted or the current chunk is finished is the delay you experience between pressing Cancel and actually stopping the render.
Following Scott Milner line of thought, the larger a render tile or bucket is, the longer it takes to render, so theoretically the longer the potential delay to cancel. The same applies for more complex algorithms like Branched Path Tracing which require more processing power and memory, and thus take longer to process.
Rendering with smaller bucket sizes may improve responsiveness and reduce cancel times, but it may do so at the expense of total render time, negatively affecting your performance for the benefit of faster cancelling, so you should weight the pros and cons of faster render or faster cancelling.