Threading in Lambda is a trap. You're fighting the runtime, not with it. Async is the right call there.
One thing though: if you're wrapping boto3, make sure you're using aioboto3 or similar. The async wrappers people write themselves often don't actually parallelize the I/O properly, just shuffle thread overhead around.
The memory win you're seeing is real. ThreadPoolExecutor keeps thread stacks alive even when idle. Asyncio tasks are basically free compared to that.
Did you hit any issues with connection pooling or Lambda's execution environment when you switched? That's usually where async setups fail in Lambda.