为什么要锁定线程?

| 我已经阅读了很多有关锁定线程的示例。但是为什么要锁定它们呢? 据我了解,当您在不加入线程的情况下启动线程时,它们将与主线程和所有其他线程竞争资源,然后执行,有时同时执行,有时不执行。 锁定是否确保线程不会同时执行? 另外,同时执行线程有什么问题?那不是更好吗? (整体执行速度更快) 锁定线程时,它会全部锁定它们还是可以选择要锁定的线程? (实际上任何锁定都可以...) 我指的是使用诸如lock()之类的锁定函数并在线程模块btw中获取...     
已邀请:
        锁使您可以强制多个线程一次访问一个资源,而不是所有线程都试图同时访问该资源。 如您所述,通常您确实希望线程同时执行。但是,假设您有两个线程,并且两个线程都正在写入同一文件。如果他们尝试同时写入同一文件,则它们的输出将混杂在一起,并且实际上没有一个线程能够成功地将其所需的内容放入文件中。 现在也许这个问题不会一直出现。大多数情况下,线程不会尝试一次全部写入文件。但是有时候,它们可能每千次运行一次。因此,也许您的bug似乎随机发生,并且难以复制,因此很难修复。啊! 也许...这发生在我工作过的一家公司中...您有这样的错误,但不知道它们在那里,因为如果您的计算机只有几个CPU,而几乎没有任何CPU,则它们很少出现您的客户中有超过4个。然后他们都开始购买16个CPU的盒子...并且您的软件运行的线程数与CPU内核数一样,因此突然您崩溃了很多,或者得到了错误的结果。 所以无论如何,回到文件。为防止线程彼此踩踏,每个线程在写入文件之前必须获得文件上的锁。一次只能有一个线程持有该锁,因此一次只能有一个线程写入文件。线程将持有该锁,直到完成写入文件为止,然后释放该锁,以便另一个线程可以使用该文件。 如果线程正在写入不同的文件,则永远不会出现此问题。因此,这是一个解决方案:让您的线程写入不同的文件,然后在必要时将它们合并。但是,这并不总是可能的。有时候,只有一种。 它不一定是文件。假设您试图简单地计算一堆不同文件中字母“ A”的出现次数,每个文件一个线程。您认为,很显然,每次看到\“ A. \”,我都会让所有线程都增加相同的内存位置,但是!当您增加用于保持计数的变量时,计算机将变量读入寄存器,对寄存器进行递增,然后将值存储回去。如果两个线程同时读取值,同时增加值并同时存储回去怎么办?他们俩都从10开始,将其增加到11,然后再存储11。因此计数器的11应该是12:您输了一个计数。 获取锁可能会很昂贵,因为您必须等到其他任何正在使用该资源的人使用完该锁。这就是为什么Python的Global Interpreter Lock是性能瓶颈。因此,您可能决定完全避免使用共享资源。每个线程都使用自己的计数,而不是使用单个内存位置来保存文件中的\“ A \”数量,而是将它们全部加到最后(类似于我建议的文件解决方案,很有趣足够)。     
首先,锁旨在保护资源。线程不是\'locked \'或\'unlocked \',而是/ acquire /一个锁(在资源上)和/ release /一个锁(在资源上)。 您确实希望线程尽可能多地并发运行,但是让我们看一下:
y=10

def doStuff( x ):
    global y
    a = 2 * y
    b = y / 5
    y = a + b + x
    print y

t1 = threading.Thread( target=doStuff, args=(8,) )
t2 = threading.Thread( target=doStuff, args=(8,) )
t1.start()
t2.start()
t1.join()
t2.join()
现在,您可能知道这些线程中的任何一个都可以先完成并打印。您可能会看到两个输出30。 但是他们可能不会。 y是共享资源,在这种情况下,读取和写入y的位是所谓的“关键部分”的一部分,应使用锁进行保护。原因是您没有工作单元:任何一个线程都可以随时获取CPU。 这样思考: t1正在愉快地执行代码,并且命中
a = 2 * y
现在t1的a = 20并停止执行一段时间。 t2处于活动状态,而t1等待更多的CPU时间。 t2执行:
a = 2 * y
b = y / 5
y = a + b + x
此时,全局变量y = 30 t2停止片刻停止,t1再次加速。它执行:
b = y / 5
y = a + b + x
由于在设置b时y为30,因此b = 6且y现在设置为34。 打印的顺序也不是确定的,您可能会先获得30个或首先获得34个。 使用锁,我们将拥有:
global l
l = threading.Lock()
def doStuff( x ):
    global y
    global l
    l.acquire()
    a = 2 * y
    b = y / 5
    y = a + b + x
    print y
    l.release()
这必定使这段代码线性化-一次仅一个线程。但是,如果整个程序是顺序的,则无论如何都不要使用线程。这个想法是,您可以根据执行外部锁并并行运行的代码所占的百分比来提高速度。这是(一个原因)为什么在2核系统上使用线程不会使所有性能提高一倍。 锁本身也是一个共享资源,但是它必须是:一个线程获取了锁,所有其他试图获取/ same /锁的线程都将阻塞,直到被释放。一旦释放,第一个向前移动并获取锁的线程将阻塞所有其他等待线程。 希望这足以继续下去!     

要回复问题请先登录注册