我正在用ANSI C(1972)编写一个程序,我必须使用固定数量的线程。我基本上读了一个包含纬度和经度数据的.csv
等记录的大文件,我必须处理它们。问题是我不能在100.000.000行文件上等待2周,我需要使用threads
或forking
。
基本上我会像这样阅读.txt
文件
FILE *file2 = fopen ( lat_long_file, "r" );
if (file2 != NULL)
{
char line2 [128];
while (fgets(line2, sizeof line2, file2) != NULL)
{
//fputs(line2, stdout);
char *this_record = trimqq(line2);
// .....
// ..... STUFF TO DO (here i must send data to thread function like in JAVA)
// Thread temp_thread = new Thread(new ThreadClass(arguments ....));
// temp_thread.start(); <- this is how i would do if i was programming in JAVA
// .....
}
}
main_1.c (使用pthread.h
进行线程处理)
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 10
static int current_threads = 0;
void *wait(void *t)
{
int i;
long tid;
tid = (long)t;
// sleep(1);
system("sleep 3; date;");
printf("Sleeping in thread\n");
printf("Thread with id %lu ...exiting\n",tid);
pthread_exit(NULL);
}
int main ()
{
int rc;
int i;
pthread_t threads[NUM_THREADS];
pthread_attr_t attr;
void *status;
// Initialize and set thread joinable
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for( i=0; i < NUM_THREADS; i++ )
{
// cout << "main() : creating thread, " << i << endl;
rc = pthread_create(&threads[i], NULL, wait, (void *)(intptr_t)i );
if (rc)
{
// cout << "Error:unable to create thread," << rc << endl;
exit(-1);
}
}
// free attribute and wait for the other threads
pthread_attr_destroy(&attr);
for( i=0; i < NUM_THREADS; i++ )
{
rc = pthread_join(threads[i], &status);
if (rc)
{
printf("Error:unable to join %d\n",rc);
exit(-1);
}
printf("Main: completed thread id : %d",i);
printf(" exiting with status : %p\n",status);
}
printf("Main: program exiting.\n");
pthread_exit(NULL);
}
我输入此ID的输出
Sleeping in thread
Sleeping in thread
Thread with id 5 ...exiting
Sleeping in thread
Thread with id 0 ...exiting
Sleeping in thread
Sleeping in thread
Sleeping in thread
Thread with id 9 ...exiting
Thread with id 1 ...exiting
Sleeping in thread
Sleeping in thread
Thread with id 7 ...exiting
Thread with id 3 ...exiting
Thread with id 2 ...exiting
Thread with id 6 ...exiting
Sleeping in thread
Thread with id 4 ...exiting
Sleeping in thread
Thread with id 8 ...exiting
Main: completed thread id : 0 exiting with status : (nil)
Main: completed thread id : 1 exiting with status : (nil)
Main: completed thread id : 2 exiting with status : (nil)
Main: completed thread id : 3 exiting with status : (nil)
Main: completed thread id : 4 exiting with status : (nil)
Main: completed thread id : 5 exiting with status : (nil)
Main: completed thread id : 6 exiting with status : (nil)
Main: completed thread id : 7 exiting with status : (nil)
Main: completed thread id : 8 exiting with status : (nil)
Main: completed thread id : 9 exiting with status : (nil)
Main: program exiting.
执行时间为3秒
如果我将system("sleep 3; date;");
更改为system("sleep 10; date;");
,执行时间将为10秒,而我希望每次调用void *wait(void *t)
函数时都会睡觉...
main_2_fork (我也尝试过fork,但没有用)
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
#define MAX_COUNT 200
#define BUF_SIZE 100
int random_number(int min_num, int max_num);
void main(void)
{
int numforks = 0;
int maxf = 5;
int status;
char buf[BUF_SIZE];
pid_t PID;
int job = 0;
for(job; job <= 10; job++)
{
// fork() = make a copy of this program from this line to the bottom
PID = fork();
int fork_id = random_number(1000000,9999999);
if (PID < 0)
{
// if -1 then couldn't fork ....
fprintf(stderr, "[!] Couldn't fork!\n");
exit(1);
}
if (( PID == 0 ))
{
// 0 = has created a child process
exit(0);
}
else
{
// means that PID is 1 2 3 .... 30000 44534 534634 .... whatever
// increment the fork count
numforks++;
sprintf(buf, "FORK[#%d] BEGIN pid=%d num_forks=%d\n",fork_id,PID,numforks);
write(1, buf, strlen(buf));
// sleep(random_number(1,2));
char str[300];
sprintf(str,"sleep %d; ps ax | wc -l",random_number(1,4));
puts(str);
// OUTPUT COMMAND BEGIN
FILE *command_execute = popen(str, "r");
char buf[256];
int increment = 0;
while (fgets(buf, sizeof(buf), command_execute) != 0)
{
printf("LINE[%d]:%s",increment,buf);
increment++;
break;
}
pclose(command_execute);
// OUTPUT COMMAND END
// block to not do extra forks
if (numforks > maxf)
{
for (numforks; numforks > maxf; numforks--)
{
PID = wait(&status);
}
}
sprintf(buf, "FORK[#%d] END pid=%d num_forks=%d\n",fork_id,PID,numforks);
write(1, buf, strlen(buf));
}
// sleep(1);
}
}
int random_number(int min_num, int max_num)
{
int result=0,low_num=0,hi_num=0;
if(min_num<max_num)
{
low_num=min_num;
hi_num=max_num+1; // this is done to include max_num in output.
}
else
{
low_num=max_num+1;// this is done to include max_num in output.
hi_num=min_num;
}
srand(time(NULL));
result = (rand()%(hi_num-low_num))+low_num;
return result;
}
输出是:
FORK[#7495656] BEGIN pid=29291 num_forks=1
sleep 1; ps ax | wc -l
LINE[0]:312
FORK[#7495656] END pid=29291 num_forks=1
FORK[#9071759] BEGIN pid=29296 num_forks=2
sleep 4; ps ax | wc -l
LINE[0]:319
FORK[#9071759] END pid=29296 num_forks=2
FORK[#2236079] BEGIN pid=29330 num_forks=3
sleep 4; ps ax | wc -l
......
并且执行不是并行的...而是它逐个执行,即使fork()
函数在ps ax | grep 'fork2.exe'
中创建子进程...
这是我想要的一个例子: http://www.javacodegeeks.com/2013/01/java-thread-pool-example-using-executors-and-threadpoolexecutor.html
你放的地方让我们说5是一次最大线程。
问题
void *wait(void *t)
功能无法正常睡眠?为什么pthread
逐个执行而不是并行执行?C
?非常感谢。
答案 0 :(得分:1)
我无法评论,所以我会在这里回复。您的线程示例正好占用一个线程(您的 wait()函数)休眠的时间。这就是说,如果你用这种方式写它会更清楚:
void *some_running_task(void *t)
{
int i;
long tid = (long)t;
printf("Sleeping in thread #%lu ...\n", tid);
system("sleep 3; date;");
printf("Thread with #%lu ... exiting\n", tid);
pthread_exit(NULL);
}
正如@fuzxxl所说,标准线程库中有一个wait(),所以你不应该使用它。
所有线程都在同一时刻开始,可能是几十微秒。他们都在同一时刻开始,因此所有人都在3秒后结束。将睡眠指令更改为10秒,程序持续10秒。
你可能想要的是一个线程池,它们一直保持相同数量的线程忙,直到整个工作完成:触发一个线程,直到达到最大池数为止,只要有数据要处理即可。但是,同步线程池很容易出现死锁。你可以让每个线程处理它自己的文件部分...除非你想要的是一个线程专用于一行。
我在这里看到并行性的一个问题是序列。 如果您关心序列顺序,则线程不一定会以您读取行的顺序生成数据。因此,除非您将处理后的数据与行号一起放入数据库中,否则将丢失序列顺序。
我看到的另一个问题是输出处理过的数据。它需要适当的同步,以避免一个线程输出不要弄乱另一个( iif线程应该打印出他们的数据,当然)。
除了加快全球处理时间之外,我对这里的并行性的期望还有点不清楚。如果你想要一堆线程来处理一堆线,那么无论如何你都会遇到类似于分割你的源数据文件这样简单的东西...如果它可以完全完成的话。但是至少你可以在读取每一行时控制数据序列,然后你可以重新启动长时间运行的单线程进程而不是长时间运行的多线程应用程序。单线程应用程序比多线程应用程序更容易编程。
使用C也是强制性的,你不能使用Python或Cython吗?最大的优点是让您免于线程同步的麻烦。
无论如何,有多种方法可以加速线性数据处理。例如,UNIX sed
可用于将一定量的行传递给处理应用程序。根据需要运行尽可能多的sed | <processing app>
。或者您可能只是将数据文件的拆分部分传输到用C或Python编写的处理应用程序中。
只是成为头条新闻。