Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PythonC扩展:多线程和随机数_Python_C_Multithreading_Random - Fatal编程技术网

PythonC扩展:多线程和随机数

PythonC扩展:多线程和随机数,python,c,multithreading,random,Python,C,Multithreading,Random,我已经用C实现了一个工作队列模式(在python扩展中),我对性能感到失望 我有一个粒子列表(“元素”)的模拟,我对执行一个时间步所需的所有计算所花费的时间进行基准测试,并将其与涉及的粒子数一起记录下来。我在四核超线程i7上运行代码,因此我希望随着线程数增加到8个左右,性能会提高(下降所需的时间),但是最快的实现没有工作线程(函数只是简单地执行,而不是添加到队列中),并且随着每个工作线程,代码变得越来越慢(比每个新线程的无线程实现时间长了一步!)我快速浏览了一下我的处理器使用率应用程序,无论有多

我已经用C实现了一个工作队列模式(在python扩展中),我对性能感到失望

我有一个粒子列表(“元素”)的模拟,我对执行一个时间步所需的所有计算所花费的时间进行基准测试,并将其与涉及的粒子数一起记录下来。我在四核超线程i7上运行代码,因此我希望随着线程数增加到8个左右,性能会提高(下降所需的时间),但是最快的实现没有工作线程(函数只是简单地执行,而不是添加到队列中),并且随着每个工作线程,代码变得越来越慢(比每个新线程的无线程实现时间长了一步!)我快速浏览了一下我的处理器使用率应用程序,无论有多少线程在运行,python似乎从未真正超过130%的CPU使用率。这台机器有足够的净空,总体系统使用率约为200%

现在是我的队列实现的一部分(如下所示)正在从队列中随机选择一个项,因为每个工作项的执行都需要锁定两个元素,并且类似的元素在队列中彼此相邻。因此,我希望线程选择随机索引并攻击队列的不同位,以最小化互斥冲突

现在,我已经读到,我最初尝试使用
rand()
的速度会很慢,因为我的随机数不是线程安全的(这句话有意义吗?不确定…)

我用
random()
drand48_r
两种方法尝试了这个实现(不幸的是,后者似乎在OSX上不可用),但在统计数据方面没有任何效果

也许其他人可以告诉我问题的原因是什么?下面是代码(worker函数),如果您认为任何queue_add函数或构造函数也可能有用的话,请不要大声喊叫

void*工作线程函数(void*非类型队列){
queue_t*queue=(queue_t*)非类型化的队列;
int成功=0;
int rand_id;
长内温;
工作项*工作项到工作项=空;
int work\u items\u completed=0;
而(1){
if(pthread\u mutex\u lock(队列->mutex)){
//如果出现错误,请重试:
持续
}
而(!成功){
如果(队列->队列->计数==0){
pthread_mutex_unlock(队列->互斥);
打破
}
//从工作队列中选择一个随机项,以避免冲突元素互斥体。
rand_id=random()%queue->queue->count;
如果(!pthread\u mutex\u trylock(((工作项)队列->队列->项目[rand\u id])->mutex)){
//在工作项的两个元素上获取互斥锁。
工作时间=(工作项目时间*)队列->队列->项目[随机id];
如果(!pthread_mutex_trylock(((element_t*)work_to_do->element_1)->mutex)){
如果(!pthread\u mutex\u trylock(((element\u t*)work\u to\u do->element\u 2)->mutex)){
成功=1;
}否则{
//仅锁定元素_1和工作项:
pthread_mutex_unlock(((element_t*)work_to_do->element_1)->mutex);
pthread_mutex_unlock(work_to_do->mutex);
工作时间=零;
}
}否则{
//无法锁定元素_1,甚至没有尝试2:
pthread_mutex_unlock(work_to_do->mutex);
工作时间=零;
}
}
}
if(work_to_do==NULL){
如果(队列->队列->计数==0&&队列->退出标志){
打破
}否则{
持续
}
}
队列\删除\工作\项(队列,随机id,NULL,1);
pthread_mutex_unlock(work_to_do->mutex);
pthread_mutex_unlock(队列->互斥);
//在这一点上,我们为讨论中的两个元素提供了互斥锁,并且
//工作项不再对任何其他线程可见。我们还解锁了主线程
//共享队列,并且可以自由地对元素执行工作。
执行函数(
工作到做->互动功能,
(元素t*)工作任务->元素1,
(元素t*)要做的工作->元素2,
(模拟参数*)工作时间->参数
);
//现在,我们应该解锁两个元素:
pthread_mutex_unlock(((element_t*)work_to_do->element_1)->mutex);
pthread_mutex_unlock(((element_t*)work_to_do->element_2)->mutex);
//并释放工作项RAM:
工作项销毁((作废*)工作要做);
工作时间=零;
工作项目完成++;
成功=0;
}
返回NULL;
}

Python线程不是真正的线程。所有Python线程都在同一操作系统级线程中运行,并且由于GIL(全局解释器锁)一次执行一个。如果工作线程在上下文中的使用时间相对较长,则用进程重写代码可能会奏效

----编辑----


是的,这是c。但是吉尔仍然很重要。

它看起来不像是随机的()这是您的问题,因为无论线程数多少,它都是相同的代码。由于性能随着线程数的增加而下降,很可能您会被锁定开销所扼杀。您真的需要多个线程吗?work函数需要多长时间,您的平均队列深度是多少?随机选择项目似乎不是一个好主意。Defi如果队列计数要知道这是否是程序的瓶颈,您必须进行基准测试和检查,但这很有可能

random()
和具有隐藏状态变量的朋友可能是并行编程的严重瓶颈。如果他们是线程安全的,通常只需将访问设为静音即可,因此一切都会变慢

POSIX系统上线程安全随机生成器的可移植选择是
erand48
。与
drand48
相比,它接收状态变量作为参数。您只需在每个线程的堆栈上保留一个状态变量(它是
无符号短[3]
)并调用