Coded Web tests (and Web test plug-ins) should not block the thread
If you are using Coded web tests (or Web test plug-ins with a declarative Web test) and running the Web test in a load test, you should avoid doing anything in your code that will cause the running thread to block for a long time such as reading from a database, writing to a log file, or using thread syncronization locks. Doing so may prevent the load test engine from running as efficiently as it should, and thus reduce the load that can be generated.
The load test / Web test runtime engine is designed with the assumption that coded Web tests (and Web test plug-ins) do not block. The reason for this is that the load test runtime engine takes advantage of the async I/O capabilities of the System.Net.HttpWebRequest (which is used to send the HTTP requests) so that it does not require a separate thread for each virtual user running a test. This allows larger number of users to be simulated using less memory.
The way this works is that the load test engine has a small pool of threads (one per processor) that is used to start new Web test iterations. This includes calling the PreWebTest and the first call to the request enumerator for a coded Web test. This thread then issues the first Web test request asyncronously. As soon as that request has been issued, the thread is free to go start another Web test iteration for a different virtual user. This usually works works great, but if the coded Web test blocks in the PreWebTest event handler (or request enumerator) then this thread blocks and cannot go on to starting another Web test. If the thread blocks long enough, the result could be that the actual number of Web tests running in parallel may not reach the number of virtual users specified in the load test.
To complete the explanation: the thread pool mentioned above is only used to start the Web test and run the first request. When a Web test request completes asyncronously, the completion of request is processed on one of the threads in the .NET I/O completion thread pool. The depedent requests are then submitted (again async) on one of these threads. When think time is enabled, there is yet another thread that submits async requests after the appropriate think time has passed.
A good way to tell if your Web test code is using too much time is to monitor the performance counter "% Time in WebTest Code". You can find this performance counter in the load test results viewer's "Counters" tree under "Overall" / "Test" and add it to one of the graphs.