There is a select statement that I have been using to determine whether or not my CLR assembly is taking the mickey with the amount of processing time it is using.
select os.task_address,os.state,os.last_wait_type,clr.state,clr.forced_yield_count
from sys.dm_os_workers os
inner join sys.dm_clr_tasks clr on os.task_address = clr.sos_task_address
where clr.type = 'E_TYPE_USER'
The last column is the important one. If the forced_yield_count is anything but zero then SQL has told the CLR it has to yield its processing. I had a similar problem with a loop I was having to do that took too long to complete. I fixed it by putting in the following lines which yields my thread back to SQL.
nSleepCounter++;
if (nSleepCounter > 5000)
{
nSleepCounter = 0;
System.Threading.Thread.Sleep(0);
}