Haskell threads are exceedingly light weight. What is more, GHCs IO monad uses event driven scheduling much of the time, meaning ordinary Haskell code is like continuation passing style node.js code (only compiled to native code and run with multiple CPUs...)
Your example is trivial
import Control.Concurrent.Async
--given a list of requests
requests :: [IO Foo]
--you can run them concurrently
getRequests :: IO [Foo]
getRequests = mapConcurrently id requests
Control.Concurrent.Async
is probably exactly what you are looking for with respect to a library for futures. Haskell should never choke on mere thousands of (ordinary) threads. I haven't ever written code that uses millions of IO threads, but I would guess your only problems would be memory related.