Многопоточность, проходящая через массив структур в C

Я написал программу, которая получает на вход текстовый файл и возвращает на выходе другой текстовый файл. Текстовый файл создается с помощью скрипта (python) внутри 3D-приложения (Blender) и содержит список вершин, являющихся частью квадратной сетки. Программа получает эти данные, сохраняет их в структуре и возвращает список вершин, образующих меньший квадрат. Затем 3D-приложение, опять же со скриптом, считывает эти вершины и отделяет их от исходной сетки. Проделав это несколько раз, исходная сетка будет разделена на множество квадратов одинаковой площади. К СЕЙЧАС ЭТО РАБОТАЕТ ;) Но это ужасно низко.. Когда это делается на 200 тысячах вершин, это занимает некоторое время, но запуск на 1 тысяче вершин занимает целую вечность.

Вот источник:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef struct{
    int index;
    float x,y,z;
} vertex;
vertex *find_vertex(vertex *list, int len)
{
    int i;
    vertex lower,highter;
    lower=list[0];
    highter=list[1];
//find the lower lefter and the upper righter vertices
    for(i=0;i<len;i++)
    {
        if ((list[i].x<=lower.x) && (list[i].y<=lower.y))
            lower=list[i];
        if ((list[i].x>=highter.x) && (list[i].y>=highter.y))
            highter=list[i];
    }
    vertex *ret;//create a pointer for returning 2 structs
    ret=(vertex*)malloc(sizeof(vertex)*2);
    if (ret==NULL)
    {
        printf("Can't allocate the memory");
        return 0;
    }
    ret[0]=lower;
    ret[1]=highter;
    return ret;
}
vertex *square_list_of_vertex(vertex *list,int len,vertex start, float size)
{
    int i=0,a=0;
    unsigned int *num;
    num=(int*)malloc(sizeof(unsigned int)*len);
    if (num==NULL)
    {
        printf("Can't allocate the memory");
        return 0;
    }
    //controlls if point is in the right position and adds its index in the main list in another array
    for(i=0;i<len;i++)
    {
        if ((list[i].x-start.x)<size && (list[i].y-start.y<size))
        {
            if (list[i].y-start.y>-size/100)//it was adding also wrong vertices. This line is to solve a bug
            {
                num[a]=i;
                a++;//len of the return list
            }
        }
    }
    //create the list with the right vertices
    vertex *retlist;
    retlist=(vertex*)malloc(sizeof(vertex)*(a+1));
    if (retlist==NULL)
    {
        printf("Can't allocate the memory");
        return 0;
    }
    //the first index is used only as an info container
    vertex infos;
    infos.index=a+1;
    retlist[0]=infos;
    //set the value for the return pointer
    for(i=1;i<=a;i++)
    {
        retlist[i]=list[num[i-1]];
    }
    return retlist;
}
//the function that pass the data to python
void return_funct_1(vertex lower,vertex highter)
{
    FILE* ret;
    ret=fopen("max_min.txt","w");
    if (ret==NULL)
    {
        printf("Error opening the file\n");
        return;
    }
    fprintf(ret,"%i\n",lower.index);
    fprintf(ret,"%i\n",highter.index);
    fclose(ret);
}
//the function that pass the data to python
void return_funct_2(vertex *squarelist)
{
    FILE* ret;
    int i,len;
    ret=fopen("square_list.txt","w");
    if (ret==NULL)
    {
        printf("Error opening the file\n");
        return;
    }
    len=squarelist[0].index;
    for(i=1;i<len;i++)
    {
        //return all the informations
        //fprintf(ret,"%i %f %f %f\n",squarelist[i].index,squarelist[i].x,squarelist[i].y,squarelist[i].z);

        //just return the index(it's enought for the python script)
        fprintf(ret,"%i\n",squarelist[i].index);
    }
    fclose(ret);
}
//argv:
//function[1/2] number_of_vert(int) size_of_square(int) v_index(int) v_xcoord(float) v_ycoord(float) v_zcoord(float)...
//example of file: 2 4 2 0 1 2 3 1 1 2 3 2 1 2 3 3 1 2 3 4 1 2 3 //function 1, number of ver=4, size=2 and then the 4 vertex with their coords
int main(int argc, char *argv[])
{
    if(argc==1)
    {
        printf("%s need a path to a vectorlist file\n",argv[0]);
        return 0;
    }
    FILE* input;
    input=fopen(argv[1],"r");
    if (input==NULL)
    {
        printf("Error opening the file\n");
        return(0);
    }
    int func=0,i=0,a=0,u=0;
    char read;
    char* argument;
    argument=(char*)malloc(sizeof(char)*50);//yeah, i know, i should use list instead of an array, but when i first coded this i was quite in hurry (and i'm still  learning ) 
    //get the first paramater in the file
    argument[0]=fgetc(input);
    argument[1]='\0';
    func=atoi(argument);
    //skipp the space
    read=fgetc(input);
    //get the number of vertices;
    i=0;
    do {
        read=fgetc(input);
        argument[i]=read;
        i++;
    }while(read!=' ' && !feof(input) );
    //set the end of the string
    argument[i]='\0';
    //set the variable to the correct integer value;
    int vnumber=atoi(argument);
    i=0;
    do {
        read=fgetc(input);
        argument[i]=read;
        i++;
    } while(read!=' ' && !feof(input));
    //set the end of the string
    argument[i]='\0';
    float sqsize=atof(argument);
    vertex *list;
    //allocate memory in the array to fit the number of vertex needed
    list=(vertex*)malloc(sizeof(vertex)*vnumber);
    //control if the memory get allocated
    if (list==NULL)
    {
        printf("Can't allocate the memory");
        return 0;
    }
    //do the cycle for each vertex
    for(u=0;u<vnumber;u++)
    {
        //read the number and assign it to the proper value of the vertex
        for(a=0;a<4;a++)
        {
            i=0;
            do
            {
                read=fgetc(input);
                argument[i]=read;
                i++;
            } while(read!=' ' && !feof(input));
            argument[i]='\0';

            if(a==0)
                list[u].index=atoi(argument);
            if(a==1)
                list[u].x=atof(argument);
            if(a==2)
                list[u].y=atof(argument);
            if(a==3)
                list[u].z=atof(argument);
        }
    }
    //close the file
    fclose(input);
    if (func==1)
    {
        //find the lowest vertex and the higtest vertex
        vertex lower;
        vertex highter;
        vertex *lohi;
        lohi=(vertex*)find_vertex(list, vnumber);
        lower=lohi[0];
        highter=lohi[1];
        free(lohi);
        return_funct_1(lower,highter);//the function that return the data to python
        return 1;
    }
    if(func==2)
    {
        //find the list to return
        vertex *lohi;
        lohi=(vertex*)find_vertex(list, vnumber);
        vertex lower;
        lower=lohi[0];
        free(lohi);
        return_funct_2(square_list_of_vertex(list,vnumber, lower, sqsize));//the function that return the data to python
        return 1;
    }
    printf("Function argument was wrong: nothing was done\n");
}

Я был бы очень признателен за любую помощь в создании этого многопоточного .. Работа с действительно большими данными занимает целую вечность (сегодня я пробовал с текстовым файлом размером 50 МБ, и через 20 минут он запускался только 30 раз (на 26000 мне нужно) ), и поскольку почти все компьютеры, которые будут использовать это, будут иметь как минимум 4 ядра, я бы очень хотел, чтобы он был многопоточным! Спасибо за совет! :)

Ps: если вам нужно, я тоже могу опубликовать код скрипта Python, но он довольно полон обращений к внутреннему API программы, поэтому я действительно не знаю, будет ли это полезно.


person Makers_F    schedule 26.01.2011    source источник
comment
Какой именно здесь конкретный вопрос?   -  person Oliver Charlesworth    schedule 27.01.2011
comment
Вопрос: Можете ли вы помочь мне сделать это многопоточным?   -  person Greg Buehler    schedule 27.01.2011
comment
@Greg: Однако не очень конкретный вопрос!   -  person Oliver Charlesworth    schedule 27.01.2011
comment
никто еще не проголосовал за закрытие. И я дал не очень конкретный ответ.   -  person CashCow    schedule 27.01.2011
comment
@ Оли, это лучше, чем прямо. Как я могу сделать это лучше?. Я думаю, что этот вопрос является главным кандидатом на только что опубликованный codereview.stackexchange.com.   -  person Greg Buehler    schedule 27.01.2011
comment
Что заставляет вас думать, что многопоточность сделает его быстрее? Возможно, вам следует больше инвестировать в то, чтобы сделать ваши структуры более удобными для поиска и сортировки... Те обходы линейных массивов, которые вы так щедро используете, требуют времени.   -  person Remus Rusanu    schedule 27.01.2011


Ответы (2)


Я не собираюсь работать конкретно с вашим кодом, но ваш алгоритм может применить Map и Reduce.

Это статья о том, как вы можете использовать его в C:

http://pages.cs.wisc.edu/~gibson/mapReduceTutorial.html

person CashCow    schedule 26.01.2011

Когда я профилирую ваш код, работающий с образцом набора данных из 2 миллионов случайных вершин, с исходным файлом, предварительно загруженным в кеш страницы, узким местом является преобразование строк в числа с плавающей запятой (хотя он по-прежнему выполняется всего за 5 секунд — так что это не это медленно).

Возможно многопоточное преобразование строк в числа с плавающей запятой, и при тщательном кодировании вы получите некоторые преимущества таким образом. Однако вы получите гораздо большую отдачу, если вместо этого измените код Python, чтобы записывать числа с плавающей запятой в двоичном формате, который может быть загружен непосредственно кодом C (с fread()). Я считаю, что вы можете использовать struct.pack на стороне Python для достижения этой цели.

Обрабатывающая часть вашего кода, безусловно, тоже может быть улучшена, но пока она не станет узким местом, я бы не стал об этом беспокоиться.

person caf    schedule 27.01.2011
comment
Спасибо тебе большое! Теперь я изучу, как сохранять файлы bin с помощью python. Ps: какую программу вы использовали для профилирования кода? - person Makers_F; 27.01.2011