锁对于性能的影响

很偶然的机会发现了无锁队列,然后又很偶然的接触到并行编程,虽然还没弄明白内存屏障等问题,但是历史遗留下一小段测试代码,在这段测试代码中我用分别用lock-free或lock-based方式将一个变量进行自增, 效果竟然差的惊人, 肉眼都能感觉到效率不止差了至少四倍之多。下面看代码:

#include <Windows.h>

#define	LOCK_FREE	1

int cnt;
HANDLE hMutex;

static DWORD WINAPI work_thread(void *param)
{
	int i;
	for (i = 0; i < 1000000; i++) {
		#if LOCK_FREE
		//WaitForSingleObject(hMutex, -1);
		InterlockedIncrement((unsigned long *)&cnt);
		//ReleaseMutex(hMutex);
                #else
		WaitForSingleObject(hMutex, -1);
		cnt++;
		ReleaseMutex(hMutex);

                #endif
	}

        return 0;
}

HANDLE thread_begin(int a)
{
        HANDLE hThread = CreateThread(NULL, 0, work_thread, (void *)a, 0, NULL);

	return hThread;

        return 0;
}


int main(int argc, _TCHAR* argv[])
{
	HANDLE h1, h2;

	hMutex = CreateMutex(NULL, FALSE, NULL);

	h1 = thread_begin(0);
	h2 = thread_begin(1);

	WaitForSingleObject(h1, -1);
	WaitForSingleObject(h2, -1);

	printf("%dn", cnt);

	return 0;
}

在这里我使用LOCK_FREE宏来进行切换lock-free方式还是lock-based方式,虽然没有计算时间,但是肉眼都能大概比较出效率至少差了四倍。另外有一点要说的是,这里只是开了两个线程,而且只做了变量自增而已,试想在其他高并发的场合,那么lock-based效率或许将远低于现在的测试情况,所以锁是效率的大敌之一。当然我现在还不太敢用无锁,因为我还没有搞懂什么时间用内存屏障。

————————————————————————–
为了证明是由于资源冲突而不是函数调用拖效率的后腿,可以将main函数中的两句改为如下:

h1 = thread_begin(0);
Sleep(1000);
h2 = thread_begin(1);

Sleep(1000)是为了等第一个线程跑完,这样两个线程跑的次数一样,但是将不再会产生资源冲突, 而且可以看到就算我们延时了1s,但效率远高于两个线程并发执行.



评论

  1. 你丫这函数都不加锁,跑起来肯定乱的一团糟

  2. @丁松 你没看到, 没加锁的是使用的无锁系列函数, 你跑跑看结果会令你惊讶

  3. […] 典型的生产者消费者模式. 最坏情况是1个线程生产, 64个线程消费. 以前对锁的效率测试过, 所以对于这种线程极多的情况下我是很忌讳用锁的. […]

发表评论