Multithreading 如何计算多线程进程的总计算时间

Multithreading 如何计算多线程进程的总计算时间,multithreading,algorithm,math,parallel-processing,Multithreading,Algorithm,Math,Parallel Processing,我有一组任务,我们称之为T[],其中每个任务T[I]需要一定的时间T(T[I])来处理。任务由X线程并行处理(这并不是说多个线程在单个任务上协同工作,而是多个线程在处理多个任务,每个线程执行一个任务,然后执行下一个任务,以此类推) 现在,我想计算处理所有任务所需的预期总时间。当执行顺序(大致)确定时,只要模拟测试运行是解决方案,就很容易了。我只是使用了真正的处理代码,并将其替换为一个简单的Thread.sleep,同时在任务预计需要处理的时间内进行睡眠(仅解释为毫秒以缩小其规模)。最后,我只是扩

我有一组任务,我们称之为
T[]
,其中每个任务
T[I]
需要一定的时间
T(T[I])
来处理。任务由
X
线程并行处理(这并不是说多个线程在单个任务上协同工作,而是多个线程在处理多个任务,每个线程执行一个任务,然后执行下一个任务,以此类推)


现在,我想计算处理所有任务所需的预期总时间。当执行顺序(大致)确定时,只要模拟测试运行是解决方案,就很容易了。我只是使用了真正的处理代码,并将其替换为一个简单的Thread.sleep,同时在任务预计需要处理的时间内进行睡眠(仅解释为毫秒以缩小其规模)。最后,我只是扩大了所花的时间,结果非常好。我在5个线程上运行了近100个任务,执行时间相差很大。估计是1小时39分钟,而真正的跑步只差3分钟

            long startSim = currentTimeMillis();
            List<Integer> taskTimes = parallelTests.getRuntimesForAllTests(); // ordered from longest time
            ThreadPoolExecutor simulationExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(threadCount);
            taskTimes.forEach(taskTime -> simulationExecutor.submit(() -> {
                try {
                    Thread.sleep(taskTime); // this is really seconds, but we just take it as milliseconds
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }));
            simulationExecutor.shutdown();
            simulationExecutor.awaitTermination(1, MINUTES);
            long stopSim = currentTimeMillis();
            long timeNeeded = stopSim - startSim;
            // now just multiply it *1000 to scale it up to seconds again, and that's your result
long startSim=currentTimeMillis();
List taskTimes=parallelTests.getRuntimesForAllTests();//从最长时间订购
ThreadPoolExecutor simulationExecutor=(ThreadPoolExecutor)Executors.newFixedThreadPool(threadCount);
taskTimes.forEach(taskTime->simulationExecutor.submit(()->{
试一试{
Thread.sleep(taskTime);//这实际上是秒,但我们只把它当作毫秒
}捕捉(中断异常e){
e、 printStackTrace();
}
}));
simulationExecutor.shutdown();
模拟执行器等待终止(1分钟);
long stopSim=currentTimeMillis();
所需时间长=stopSim-startSim;
//现在把它乘以1000,再放大到秒,这就是你的结果

我假设任务是按照提供的顺序安排的,并且每个任务都转到第一个空闲线程。如果这些假设是正确的,那么就不存在有意义的非确定性——一个任务可能会转到任何空闲线程(如果有多个线程),但这对总运行时间没有影响

在这种情况下,我们可以使用大小为X的最小堆(其中X是线程数)来模拟此情况,堆中的值表示其中一个线程的空闲时间。对于每个任务,我们从堆中弹出最早的空闲线程,然后将其按完成此新任务的时间向后推

安排好所有任务后,我们可以获取堆中的最大值,即所有任务完成的时间

这是Python中相对较少的代码:

import heapq

def compute_time(tasks, X):
    threads = [0] * X
    for t in tasks:
        heapq.heappush(threads, heapq.heappop(threads) + t)
    return max(threads)

print compute_time([3, 2, 1], 2)
print compute_time([5, 4, 3, 3, 2, 1, 1], 3)
或在Java中:

import java.util.*;

class Threads {
    public static void main(String args[]) {
        int totalTime1 = computeTotalTime(Arrays.asList(3, 2, 1), 2);
        System.out.println("totalTime1: " + totalTime1);

        int totalTime2 = computeTotalTime(Arrays.asList(5, 4, 3, 3, 2, 1, 1), 3);
        System.out.println("totalTime2: " + totalTime2);
    }

    static int computeTotalTime(List<Integer> task, int threads) {
        PriorityQueue<Integer> q = new PriorityQueue<Integer>();
        for (int i = 0; i < threads; i++) q.add(0);
        for (int t : task) q.add(q.poll() + t);
        int max = 0;
        while(!q.isEmpty()) max = q.poll();
        return max;
    }
}
import java.util.*;
类线程{
公共静态void main(字符串参数[]){
int totalTime1=computeTotalTime(Arrays.asList(3,2,1,2));
System.out.println(“totalTime1:+totalTime1”);
int totalTime2=计算时间(Arrays.asList(5,4,3,3,2,1,1,3);
System.out.println(“totalTime2:+totalTime2”);
}
静态int计算时间(列出任务,int线程){
PriorityQueue q=新的PriorityQueue();
对于(inti=0;i
答案取决于调度算法。例如,如果您有4个作业(每个作业的持续时间为10秒)和一个作业(每个作业的持续时间为100秒)以及4个线程,则如果计划程序将前4个作业(每个作业的持续时间为10秒)作为第一组,然后在第二轮中单独运行100秒作业,则持续时间将为110秒。如果调度程序先按最长作业排序,则持续时间将为100秒。对,我忘记添加此信息。我已经更新了帖子。所以我知道任务将按照从最长运行到最短运行的顺序进行处理,但我仍然不知道如何计算。你说的是“预期”时间,但从描述来看,调度似乎是确定的。如果它确实是确定性的,并且下一个任务被分配给最早的空闲线程,那么很容易进行模拟。如果它不是确定性的,这个问题需要编辑来解释非确定性的来源。是的,请看我自己编辑的答案。事实上,我最终模拟了它。它不是超级精确,但我的测试表明它足够精确。例如,我做了一次跑步,估计需要8分钟,结果花了9分钟。我认为我关于模拟的回答是正确的,但我不能接受我自己的回答。上面提到任务是在“最长优先”的基础上处理的,而不是按照呈现的顺序处理的。@MarkSetchell问题还注意到任务队列是按最长优先排序的,因此代码按原样工作。谢谢。我不知道像Java中的python代码这样的函数,所以对我来说,下一个最好的方法就是实际模拟它,看看我自己的答案。嗯,如果你只对Java解决方案感兴趣,最好用
Java
标记你的问题。我并不是真的用Java编程,但是Python的minheap的Java等价物是Java.util.PriorityQueue。我添加了一个代码的翻译。现在我已经玩过了,这是相当整洁的完成-可惜我不能再投票了!对于三个线程上的任务[3,2,2,2],我认为这将在第一个线程上安排最终任务,给出5的总运行时间。但是它应该有运行时4:最后的任务可以安排在另外两个线程中的一个上。一般来说,我很难理解为什么这段代码会模拟一个真实的系统——实际上,一个任务会一直保持到线程空闲,然后分配给它。在您的代码中,这相当于将任务分配给总时间最小的线程,而不是最小的线程