Ответ 1
Реформирование вопроса
Я написал многопоточное приложение, которое занимает X секунд для выполнения на моей машине K-core.
Как оценить, сколько времени потребуется программе для работы на одноядерном компьютере?
Эмпирически
Очевидным решением является получение компьютера с одним ядром и запуск вашего приложения, а также использование времени настенных часов и/или времени процессора по вашему желанию.
... О, подождите, ваш компьютер уже имеет одно ядро (у него также есть другие, но нам не нужно будет их использовать).
Как это сделать, будет зависеть от операционной системы, но один из первых результатов, которые я нашел в Google, объясняет несколько подходов для Windows XP и Vista.
http://masolution.blogspot.com/2008/01/how-to-use-only-one-core-of-multi-core.html
После этого вы могли:
- Присвойте свой процесс приложения единому ядру. (вы также можете сделать это в своем коде).
- Начните свою операционную систему только зная об одном из ваших ядер. (а затем переключиться обратно)
Независимый Parallelism
Оценка этого аналитически требует знания вашей программы, метода parallelism и т.д.
В качестве простого примера предположим, что я пишу многопоточную программу, которая вычисляет десятимиллиардную десятичную цифру pi и десятимиллиардную десятичную цифру e.
Мой код выглядит так:
public static int main()
{
Task t1 = new Task( calculatePiDigit );
Task t2 = new Task( calculateEDigit );
t1.Start();
t2.Start();
Task.waitall( t1, t2 );
}
И так бывает, когда граф выглядит так:
Очевидно, что они независимы.
В этом случае
- Вычисляет времяPayDigit() самостоятельно.
- Вычисляет время calcEDigit().
- Добавьте время вместе.
2-этапный трубопровод
Когда задачи не являются независимыми, вы не сможете просто добавить отдельные моменты вместе.
В следующем примере я создаю многопоточное приложение: сделайте 10 изображений, преобразуйте их в оттенки серого, а затем запустите алгоритм определения линии. По какой-то внешней причине каждое изображение не может быть обработано не в порядке. Из-за этого я создаю шаблон конвейера.
Мой код выглядит примерно так:
ConcurrentQueue<Image> originalImages = new ConcurrentQueue<Image>();
ConcurrentQueue<Image> grayscaledImages = new ConcurrentQueue<Image>();
ConcurrentQueue<Image> completedImages = new ConcurrentQueue<Image>();
public static int main()
{
PipeLineStage p1 = new PipeLineStage(originalImages, grayScale, grayscaledImages);
PipeLineStage p2 = new PipeLineStage(grayscaledImages, lineDetect, completedImages);
p1.Start();
p2.Start();
originalImages.add( image1 );
originalImages.add( image2 );
//...
originalImages.add( image10 );
originalImages.add( CancellationToken );
Task.WaitAll( p1, p2 );
}
Выполняется центрирование данных перед графиком:
Если эта программа была разработана как последовательная программа для начала, по причинам кэша было бы более эффективно принимать каждое изображение по одному и переводить их до завершения, прежде чем переходить к следующему изображению.
В любом случае, мы знаем, что GrayScale() будет вызван 10 раз, а LineDetection() будет вызван 10 раз, поэтому мы можем просто провести время каждый раз, а затем умножить их на 10.
Но как насчет затрат на толкание/выскакивание/опрос ConcurrentQueues?
Предполагая, что изображения большие, это время будет незначительным.
Если на каждом этапе есть миллионы небольших изображений, у многих потребителей, то вы, вероятно, обнаружите, что накладные расходы на блокировки, мьютексы и т.д. очень малы, когда программа запускается последовательно (при условии, что количество работа, выполняемая в критических разделах, мала, например, внутри параллельной очереди).
Затраты контекстного переключения?
Взгляните на этот вопрос:
Как оценить затраты на переключение контекста потока?
В основном, у вас будут переключатели контекста в многоядерных средах и в одноядерных средах.
Накладные расходы для выполнения контекстного коммутатора довольно малы, но они также происходят очень много раз в секунду.
Опасность состоит в том, что кеш полностью прерывается между коммутаторами контекста.
Например, в идеале:
- image1 загружается в кеш в результате выполнения GrayScale
- LineDetection будет работать намного быстрее на image1, так как он находится в кеше
Однако это может произойти:
- image1 загружается в кеш в результате выполнения GrayScale
- image2 загружается в кеш в результате выполнения GrayScale
- Теперь этап 2 трубопровода запускает LineDetection на image1, но image1 больше не находится в кеше.
Заключение
Ничто не сравнится с временем в той же среде, в которой он будет запущен.
Лучше всего симулировать эту среду, а также вы можете.
Независимо от того, что понимание дизайна вашей программы должно дать вам представление о том, чего ожидать в новой среде.