Прежде всего, я согласен с Райаном в том, что этот вопрос совершенно актуален, и есть случаи, когда приоритеты потоков вообще не являются достаточными. Другие ответы кажутся очень теоретическими и бесполезными в ситуациях, когда приложение правильно спроектировано, но все еще нуждается в регулировании. Райан предлагает простое решение для случаев, когда относительно короткие задачи выполняются с высокой частотой. Однако существуют случаи, когда задача занимает очень длительное время (скажем, минуту или около того), и вы не можете или не хотите разбивать ее на более мелкие куски, между которыми вы можете выполнять регулирование. Для этих случаев может быть полезно следующее решение:
Вместо того, чтобы реализовывать регулирование в бизнес-коде, вы можете спроектировать сам алгоритм, чтобы он работал на полную мощность и просто регулировал поток, который выполняет операцию «извне». Общий подход такой же, как и в ответе Райана: рассчитайте время приостановки на основе текущего использования и приостановите поток на этот промежуток времени, прежде чем возобновить его снова. Учитывая процесс, который вы хотите ограничить, это логика:
public static class ProcessManager
{
[Flags]
public enum ThreadAccess : int
{
TERMINATE = (0x0001),
SUSPEND_RESUME = (0x0002),
GET_CONTEXT = (0x0008),
SET_CONTEXT = (0x0010),
SET_INFORMATION = (0x0020),
QUERY_INFORMATION = (0x0040),
SET_THREAD_TOKEN = (0x0080),
IMPERSONATE = (0x0100),
DIRECT_IMPERSONATION = (0x0200)
}
[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll")]
static extern uint SuspendThread(IntPtr hThread);
[DllImport("kernel32.dll")]
static extern int ResumeThread(IntPtr hThread);
[DllImport("kernel32.dll")]
static extern int CloseHandle(IntPtr hThread);
public static void ThrottleProcess(int processId, double limit)
{
var process = Process.GetProcessById(processId);
var processName = process.ProcessName;
var p = new PerformanceCounter("Process", "% Processor Time", processName);
while (true)
{
var interval = 100;
Thread.Sleep(interval);
var currentUsage = p.NextValue() / Environment.ProcessorCount;
if (currentUsage < limit) continue;
var suspensionTime = (currentUsage-limit) / currentUsage * interval;
SuspendProcess(processId);
Thread.Sleep((int)suspensionTime);
ResumeProcess(processId);
}
}
private static void SuspendProcess(int pid)
{
var process = Process.GetProcessById(pid);
if (process.ProcessName == string.Empty)
return;
foreach (ProcessThread pT in process.Threads)
{
IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);
if (pOpenThread == IntPtr.Zero)
{
continue;
}
SuspendThread(pOpenThread);
CloseHandle(pOpenThread);
}
}
private static void ResumeProcess(int pid)
{
var process = Process.GetProcessById(pid);
if (process.ProcessName == string.Empty)
return;
foreach (ProcessThread pT in process.Threads)
{
IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);
if (pOpenThread == IntPtr.Zero)
{
continue;
}
var suspendCount = 0;
do
{
suspendCount = ResumeThread(pOpenThread);
} while (suspendCount > 0);
CloseHandle(pOpenThread);
}
}
}
Преимущество этого решения заключается в том, что интервал проверки становится независимым от продолжительности вашей "длительной задачи". Кроме того, бизнес-логика и логика регулирования разделены. Код приостановки / возобновления навеян этой веткой . Обратите внимание, что устранение и прекращение регулирования должно быть реализовано в приведенном выше решении, это не рабочий код.