提问人:Luca Mautino 提问时间:11/16/2023 最后编辑:Peter CordesLuca Mautino 更新时间:11/17/2023 访问量:41
增加线程数会使程序变慢
Increasing the number of threads makes the program slower
问:
我目前正在尝试通过使用读写锁实现一个具有多线程访问的链表。虽然它似乎工作正常,但我一直在试图看看当我增加线程数时性能改进了什么,事实证明性能实际上变得更糟了:
- 使用 100.000 次操作和 1 个线程,运行时间为 6.59 秒
- 使用 100.000 次操作和 2 个线程,运行时间为 6.68 秒
- 使用 100.000 次操作和 4 个线程,运行时间为 6.69 秒
对于不同数量的操作和线程,模式是相同的。虽然速度放缓并不明显,但与串行版本相比,我肯定希望看到某种改进。我尝试更改链表操作的顺序以避免过多的写入锁争用,但问题仍然存在。 (此外,由于某种原因,MacOS 不允许我运行超过 200.000 次操作的程序)
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>
struct list_node_s {
int data;
struct list_node_s * next;
};
int Member(int value, struct list_node_s ** head);
int Insert(int value, struct list_node_s ** head);
int Delete(int value, struct list_node_s ** head);
void * threadOp(void * my_rank);
pthread_rwlock_t lock;
long n;
long thread_count;
struct list_node_s * head_p;
int main(int argc, char ** argv){
double i = 0;
clock_t begin = clock();
n = strtol(argv[1], NULL, 10);
thread_count = strtol(argv[2], NULL, 10);
pthread_t * thread_handles = malloc(sizeof(pthread_t) * thread_count);
long thread;
printf("Will create %ld threads \n", thread_count);
pthread_rwlock_init(&lock, NULL);
struct list_node_s head = {.data = 0, .next = NULL};
head_p = &head;
for (i = 1.0; i < n; i++){
Insert(i, &head_p);
}
for (thread = 0; thread < thread_count; thread++)
pthread_create(&thread_handles[thread], NULL, threadOp, (void *) thread);
for (thread = 0; thread < thread_count; thread++)
pthread_join(thread_handles[thread], NULL);
pthread_rwlock_destroy(&lock);
clock_t end = clock();
double time_spent = (double) (end - begin) / (CLOCKS_PER_SEC);
printf("Elapsed time %lf \n", time_spent);
}
int Member(int value, struct list_node_s ** head){
struct list_node_s * curr_p = * head;
// traverse list until end or we got to right value
while(curr_p != NULL && curr_p -> data < value)
curr_p = curr_p -> next;
if (curr_p == NULL || curr_p -> data > value){
return 0;
}
else{
return 1;
}
}
int Insert(int value, struct list_node_s ** head){
struct list_node_s * curr_p = * head;
struct list_node_s * pred_p = NULL;
struct list_node_s * temp_p;
while (curr_p != NULL && curr_p -> data < value){
pred_p = curr_p;
curr_p = curr_p -> next;
}
if (curr_p == NULL || curr_p -> data > value){
temp_p = malloc(sizeof(struct list_node_s));
temp_p -> data = value;
temp_p -> next = curr_p;
if (pred_p == NULL)
*head = temp_p;
else
pred_p -> next = temp_p;
return 1;
}
else {
return 0;
}
}
int Delete(int value, struct list_node_s ** head){
struct list_node_s * curr_p = * head;
struct list_node_s * pred_p = NULL;
while (curr_p != NULL && curr_p -> data < value){
pred_p = curr_p;
curr_p = curr_p -> next;
}
// value was found and curr_p is not null
if (curr_p != NULL && curr_p -> data == value){
// first element in list
if (pred_p == NULL){
* head = curr_p -> next;
free(curr_p);
} else{
pred_p -> next = curr_p -> next;
free(curr_p);
}
return 1;
}
// value not in list
else{
return 0;
}
}
void * threadOp(void * my_rank){
long thread = (long) my_rank;
long local_n = n / thread_count;
long a = local_n * thread;
long b = a + local_n;
printf("Thread %ld is executing\n", thread);
// half of threads will execute n members
for (long i = a; i < b; i++){
pthread_rwlock_rdlock(&lock);
Member(i % 15, &head_p);
pthread_rwlock_unlock(&lock);
if (i % 10000 == 0){
// other half will execute n/4 Ins and n/4 Del
pthread_rwlock_wrlock(&lock);
Insert(i, &head_p);
pthread_rwlock_unlock(&lock);
}
else if (i % 10002 == 0)
{
// other half will execute n/4 Ins and n/4 Del
pthread_rwlock_wrlock(&lock);
Delete(i, &head_p);
pthread_rwlock_unlock(&lock);
}
}
return NULL;
}
答: 暂无答案
评论
clock
clock_gettime
gettimeofday
CLOCK_MONOTONIC
malloc
free