get_posts() bypasses several filters that get hit when you call WP_Query. It also misses out on some performance enhancements.
10up’s Engineering Best Practices guide has some awesome tips on performance and WP_Query, and why not to use get_posts() in most circumstances.
But what has caused real problems for me is that get_posts() doesn’t expose itself to several filters called by WP_Query. That makes it incompataible with WPML, for instance, and any other plugin which has to filter calls to WP_Query to ensure the correct data is retrieved.
Just spend a few extra minutes and use WP_Query.
It doesn’t even make sense for complex queries to use get_posts since the syntax is almost identical. I never even knew get_posts was a thing until I started taking apart others’ themes. WP_Query hasn’t let me down yet 🙂
You can always just pass it suppressfilters => false. 🙂