Ответ 1
Вы выбрасываете опцию для сбора мусора, выполняемого на фоне, когда вы это делаете. Или, другими словами, ваш поток пользовательского интерфейса будет приостановлен в любом случае, независимо от того, выполняете ли вы это из рабочего потока. Единственный возможный способ быть впереди - когда GC.WaitForPendingFinalizers() занимает значительное количество времени. На самом деле это не то, чего вы когда-либо ждали, нет смысла, и если это займет больше минуты, тогда вы скрываете довольно серьезные ошибки в своем коде.
Еще одна существенная морщина заключается в том, что версия рабочей станции Windows предоставляет любой поток, которому принадлежит окно переднего плана большего кванта. Другими словами, разрешено сжигать ядро дольше, чем фоновый поток. Простой взлом, чтобы сделать Windows более восприимчивой к пользователю.
Слишком много движущихся частей, на самом деле лучше всего проверить вашу теорию, чтобы вы могли быть уверены, что запуск коллекции на рабочем месте - это то, чем вы вперед. Измерение приостановки подвески пользовательского интерфейса довольно просто, вы можете использовать таймер для этого. Событие Tick не может работать, когда поток приостановлен. Запустите новый проект Winforms, пометьте Timer в форме, установите для Interval значение 1 и Enabled равным True, добавьте ярлык и используйте этот код для измерения задержек:
int prevtick = 0;
int maxtick = -1;
private void timer1_Tick(object sender, EventArgs e) {
int tick = Environment.TickCount;
if (prevtick > 0) {
int thistick = tick - prevtick;
if (thistick > maxtick) {
maxtick = thistick;
label1.Text = maxtick.ToString();
}
}
prevtick = tick;
}
Запустите свою программу, вы увидите 16 в ярлыке. Если вы получаете меньше, то вы должны закрепить свою машину, а не иначе, что влияет на этот тест. Добавьте кнопку reset для измерения:
private void button1_Click(object sender, EventArgs e) {
maxtick = -1;
}
Добавьте флажок и другую кнопку. Мы проверим его фактическую коллекцию:
private void button2_Click(object sender, EventArgs e) {
var useworker = checkBox1.Checked;
System.Threading.ThreadPool.QueueUserWorkItem((_) => {
var lst = new List<object>();
for (int ix = 0; ix < 500 * 1024 * 1024 / (IntPtr.Size * 3); ++ix) {
lst.Add(new object());
}
lst.Clear();
if (useworker) {
GC.Collect();
GC.WaitForPendingFinalizers();
}
else {
this.BeginInvoke(new Action(() => {
GC.Collect();
GC.WaitForPendingFinalizers();
}));
}
});
}
Играйте с этим, нажмите кнопку2, чтобы начать сбор и обратите внимание на значение в ярлыке. Установите флажок, чтобы он работал на рабочем месте и сравнивался. Используйте кнопки1 до reset максимально между ними. И измените код выделения, вы, вероятно, захотите что-то сделать с растровыми изображениями, что бы вы ни делали, чтобы потребовать этот хак.
Что я вижу: ~ 220 мс задержка при выполнении коллекции в потоке пользовательского интерфейса, ~ 340 мс задержка при запуске на рабочем столе. Понятно, что это не улучшение вообще. С того места, где я сижу, ваша теория мертва в воде. Пожалуйста, попробуйте сами, у меня есть только один набор данных. Остерегайтесь, что это будет выглядеть совсем по-другому на серверной версии Windows или с помощью <gcServer=true>
в файле .config. Что-то еще, с чем вы можете играть.