Performance of an OLX crawler
You don't have to use a SemaphoreSlim because a Task is not equivalent to a Thread. It is a more abstract kind of "working item" that will be spreaded to real threads by the TPL. If you start 1000 tasks it does not mean that you create 1000 threads. When starting a task like you did (without option TaskCreationOptions.LongRunning), it will be executed on threads from the TreadPool. Therfore, the Threadpool is managing the number of threads for you and you can just start 17.901 tasks at once.



What is await Task.Delay(1) for?

If there is no reason for it, it just produces unnecessary overhead



var source =  Task.Run( () =&gt; this.GetSource(itemUrl) );


You don't need to wrap the returning taks in a new task. The following has less overhead and is functional equivalent:

var source =  this.GetSource(itemUrl);




Move the code from the finally block to the call of GetSourceAsync. There is no need to attach it via ContinueWith in the finally block.



All the points above applied yields to something like:

async Task FetchItemsDataAsync()
{
    var itemsTask = new List&lt;Task&lt;string&gt;&gt;();
    var itemParser = new ItemSourceParser();

    while (this.queue.TryDequeue(out itemUrl))
    {
        var task = Task.Run(async() =&gt;
        {
            var result = await this.GetSourceAsync(itemUrl);
            itemParser.InitializeNewItem(result);
            itemParser.TryToParse();
            Console.WriteLine(itemParser.data["Id"]);
            this.database.InsertItem(itemParser.data);
            itemParser.RefreshData();
        }
        itemsTask.Add(task);
    }

    return Task.WhenAll(itemsTask);
}