线程或进程?拥有与数据无关的任务,最好使用什么?

时间:2009-12-16 14:56:20

标签: c gcc concurrency parallel-processing

有一组N个与实时数据无关的任务。每个任务都处理一些数字数据流。每个任务的数据流来自输入端口,然后结果流被定向到输出端口。

1)什么是计算密集度较低的任务:进程或线程形式的任务?
2)最佳选择取决于可用的物理CPU内核数量吗?

提前谢谢!

7 个答案:

答案 0 :(得分:3)

线程应该具有稍​​微减少的开销,因为它们在进程中共享相同的内存空间,但是这种开销可能小到足以不影响您的程序。唯一能够确定哪种方式对你更好的方法是尝试两种方法,每种方法都需要多长时间。

答案 1 :(得分:2)

这个问题没有一个答案。举两个例子,Linux倾向于使用单独的进程。内核开发人员似乎已经投入了大量精力来优化流程切换。稍后添加了线程,并且似乎没有得到几乎同样多的关注。因此,在Linux下,单独的进程具有相当低的成本,而使用线程则不会节省大量资金。

相比之下,Windows的当前实现又回到了Windows NT。 Windows NT基于OS / 2,它从第一天开始就有线程。过程切换似乎没有像Linux那样进行优化。正如您可能期望的那样,在Windows下,进程切换和线程切换之间的差异要大得多。因此,通过在多个线程而不是多个进程中编写代码,您可以获得更多收益。

答案 2 :(得分:2)

如果您实际上不需要在任务之间共享大量状态,那么进程可能是更好的选择。线程隐含的任务之间的紧密耦合将使得提供实时保证变得更加困难 - 锁定使得证明实时行为变得更加困难。

简而言之,流程应该是您的默认选项;只有在您确定了明确的理由时才切换到线程。

答案 3 :(得分:1)

如果您的工作单位受CPU限制,最好使用进程,因为通常进程中的所有线程都在同一个内核上运行(至少在Linux中)。 每个CPU核心使用一个进程将确保每个进程获得一个实际的CPU核心。

线程的优点是在它们之间共享状态非常容易,所以如果您真正需要的是在不阻塞的情况下下载文件,或者向数据库发送查询,那么线程将是更好的选择。

实际上,我正处于编写你可能会觉得有用的东西的过程中:一个管理器会产生一些工作进程并在它们退出/死亡/死亡时重新启动它们。它已经准备好了,所以这就是:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string>

void termination_handler(int signum)
{
    printf("pid %d : signal %d caught in pid %d\n", getpid(), signum, getpid());
    kill(0, SIGTERM);
    exit(1);
}

int main(int argc ,char** argv) 
{
    if (argc > 1)
    {
        printf("pid %d : Worker code running\n", getpid());
        sleep(10);
    }
    else
    {
        printf("pid %d : manager started\n", getpid());
        // manager
        const int MAX_INSTANCES = 3;
        int numInstances = 0;

        struct sigaction new_action;
        /* Set up the structure to specify the new action. */
        new_action.sa_handler = termination_handler;
        sigemptyset(&new_action.sa_mask);
        new_action.sa_flags = 0;
        sigaction(SIGKILL, &new_action, NULL);
        sigaction(SIGTERM, &new_action, NULL);
        sigaction(SIGINT, &new_action, NULL);

        int status;
        int w;
        do
        {
            while (numInstances < MAX_INSTANCES)
            {
                int pid = fork();
                if (pid < 0)
                {
                    printf("fork failed\n");
                    exit(1);
                }
                else
                {
                    if (pid == 0)
                    {
                        char * const argv1[] = { (char*) argv[0], (char*)"worker",(char *) 0 };
                        char * const envp1[] = { (char *) 0 };
                        std::string prog = argv[0];
                        execve(prog.c_str(), argv1, envp1);
                    }
                    else
                    {
                        numInstances++;
                    }
                }
            }           

            w = waitpid(0, &status, WUNTRACED | WCONTINUED);
            if (w == -1)
            {
                perror("waitpid");
                exit(EXIT_FAILURE);
            }

            if (WIFEXITED(status))
            {
                printf("pid %d : child %d exited, status=%d\n",getpid(), w, WEXITSTATUS(status));
                numInstances--;
            }
            else if (WIFSIGNALED(status))
            {
                printf("pid %d : child %d killed by signal %d\n",getpid(), w, WTERMSIG(status));
                numInstances--;
            }
            else if (WIFSTOPPED(status))
            {
                printf("pid %d : child %d stopped by signal %d\n",getpid(), w, WSTOPSIG(status));
            }
            else if (WIFCONTINUED(status))
            {
                printf("pid %d : child %d continued\n", getpid(), w);
            }
        } 
        while (true);
        //! WIFEXITED(status) && !WIFSIGNALED(status));

        printf("pid %d : manager terminated\n", getpid());
    }
    return 0;
}

答案 4 :(得分:1)

我同意那些没有“正确”答案的答案。这在很大程度上取决于应用要求。如果没有明显的选择,我个人的选择就是线程。

但是我想知道效率方面,所以在昨晚回家之前写了一个非常简单的愚蠢测试。 “应用程序”只使用简单的除法检查计算了素数的数量。所以它纯粹是CPU绑定而没有争用其他共享资源。因此,它实际上只关注上下文切换的成本。在四核1.86GHz Xeon上运行64个实例(线程/进程)显示没有区别。每项任务都计算出10,000,000的素数。两种情况下的总时间为333秒。

当我骑自行车回家时,我发现由于没有资源争用,上下文切换将是最小的;每个线程/进程都会运行其全时片。因此,我使用Sleep(0)人为地强制每100次迭代进行上下文切换,我相信这就是我的意图(Win32)。之后,相同的测试花了343秒的线程版本和350秒的流程版本。所以线程版本显示大约1.7%的加速。没什么可写回家的。

答案 5 :(得分:0)

主题。

它简化了许多类型的开销,例如部署。它更具有前瞻性,因为在某些时候您可能希望它们进行交互(例如,写入公共日志,或者使用公共管理控制台)。

答案 6 :(得分:0)

  

1)什么在计算上不那么密集:以流程或线程形式的任务?

通常强度相同。在非常异常的情况下,线程可能不那么密集。

  

2)最佳选择取决于可用的物理CPU核心数量吗?

在不同的cpu核心上运行的两个或多个线程比单核心系统慢得多。这是超标量架构的问题。

流程是99.9%的最佳选择。

线程环境也很难调试。