Throttled execution of an enumeration of Tasks Example of use:
var users = await usernames.SelectTaskResults(GetUserDetails, 4);

where GetUserDetails(string username) is a method that calls HttpClient to access an API and returns a User object. The SelectTaskResults returns the awaited tasks. At most, there will be 4 concurrent threads calling the API at the same time for this example.
Concerns:
I'm worried .Wait() could cause a deadlock.
Code:
public static async Task&lt;IEnumerable&lt;TResult&gt;&gt; SelectTaskResults&lt;TInput, TResult&gt;(
        this IEnumerable&lt;TInput&gt; source,
        Func&lt;TInput, Task&lt;TResult&gt;&gt; taskFunc,
        int degreesOfParallelism = 1,
        bool throwFaulted = false,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        // Task.Run creates the task but it doesn't start executing immediately - for debugging
        var tasks = source
            .Select(input =&gt; Task.Run(() =&gt; taskFunc(input), cancellationToken))
            .ToArray();
        
        Parallel.ForEach(tasks,
            new ParallelOptions { MaxDegreeOfParallelism = degreesOfParallelism }
            , task =&gt;
            {
                try
                {
                    task.Wait(cancellationToken); // .Start() doesn't work for promise-like tasks
                }
                catch (Exception)
                {
                    if (throwFaulted)
                    {
                        throw;
                    }
                }
            }
        );
        
        var output = await Task.WhenAll(tasks.Where(x=&gt; !x.IsFaulted));
        
        return output.AsEnumerable();
    }
A TPL inside async implementation: mixing of implementaion concepts makes the code complicated or even buggy. Finally Parallel.ForEach is blocking the current thread which isn't allowed in async programming.
Also avoid blocking operations on Task e.g. .Wait() or .Result for not completed Task.
But I suggest totally different approach. Consider the simplified example.
public class ThrottledApiClient : IDisposable
{
    private readonly HttpClient _client;
    private readonly SemaphoreSlim _semaphore;

    public ThrottledApiClient(string baseUrl, int concurrentDegree = 0)
    {
        _client = new HttpClient();
        _client.BaseAddress = new Uri(baseUrl);
        _semaphore = new SemaphoreSlim(concurrentDegree == 0 ? Environment.ProcessorCount * 2 : concurrentDegree);
    }

    public async Task&lt;string[]&gt; PostJsonRequestsAsync(IEnumerable&lt;(string, string)&gt; requests, CancellationToken token)
    {
        List&lt;Task&lt;string&gt;&gt; tasks = new List&lt;Task&lt;string&gt;&gt;();
        // wrap the loop with try-catch (OperationCanceledException) to handle Cancellation right here if necessary
        foreach ((string path, string json) in requests)
        {
            await _semaphore.WaitAsync(token);
            tasks.Add(PostJsonAsync(path, json, token));
        }

        return await Task.WhenAll(tasks);

        // or with filter
        //await Task.WhenAll(tasks);
        //return tasks.Where(t =&gt; t.IsCompletedSucessfully).Select(t =&gt; t.Result).ToArray();
    }

    private async Task&lt;string&gt; PostJsonAsync(string url, string json, CancellationToken token)
    {
        try
        {
            using HttpContent content = new StringContent(json, Encoding.UTF8, &quot;application/json&quot;);
            using HttpResponseMessage response = await _client.PostAsync(url, content, token);
            // response.EnsureSuccessStatusCode(); // to throw on not success instead of returning result
            return await response.Content.ReadAsStringAsync(token);
        }
        // catch (HttpRequestException) 
        // catch (OperationCanceledException) { return null; } // to swallow cancellation
        finally
        {
            _semaphore.Release();
        }
    }

    public void Dispose()
    {
        _client.Dispose();
        _semaphore.Dispose();
    }
}

And the demo.
(string, string)[] requests = new (string, string)[]
{
    (&quot;/getAccounts&quot;, &quot;{...}&quot;),
    (&quot;/getMediaPath&quot;, &quot;{...}&quot;)
};

using (var api = new ThrottledApiClient(&quot;https://api.example.com&quot;, 4))
using (var cts = new CancellationTokenSource())
{
    var results = await api.PostJsonRequestsAsync(requests, cts.Token);
    //...
}

You can invoke PostJsonRequestsAsync even concurrently multiple times, even from different threads but only 4 requests will be active simoultaneously.
SemaphoreSlim is default synchronization tool in async programming for now.