Ruby在更深层次上理解线程

时间:2014-10-19 04:02:04

标签: ruby multithreading

此时我已经研究了这个主题几个星期了,我开始认为我是愚蠢的,因为我无法理解。我没有掌握这个概念。完全没有。我已经尝试了,并再次尝试过,但这并没有被吸收。所以希望这不会被认为是一个低质量的问题。我问,因为尽管我已经完成了所有的研究,并且我写了所有的练习代码,但我根本没有得到它,我无法弄明白。所以我会谈到这一点。

我一直在使用网络和Ruby工作,我的一些脚本涉及大量连接。因此,它大大减慢了脚本的性能。显然,如果我尝试连接1000个超时为1秒的主机,它需要一段时间。除非当然,我多线程我的应用程序,对吧?并发可以解决这个问题,而且确实如此!那是我发现竞争条件的时候。这就是我几周来一直在研究的问题。我可以使用并发加速我的程序,但现在,结果已损坏。研究经常导致使用互斥锁,据我所知,这使得没有线程可以同时访问任何资源。这将解决竞争条件问题,因为很明显,如果没有线程都试图访问相同的资源,那么结果不会被破坏。然而,我发现完全荒谬的是,实现一个互斥体会使应用程序表现得好像我从来没有打扰过应用程序的多线程。有什么意义呢?

这就是我的问题,创建多线程应用程序有什么用,然后添加一个互斥锁,按照定义使得只有一个线程可以一次执行代码?听起来与我完全矛盾。我真的希望这不是一个坏的或无用的问题,或者显示缺乏研究。我真诚地一直在研究和努力理解如何正确地多线程我的代码,没有遇到竞争条件,几周,我只是没有得到它。这是一个与编程相关的问题,我不相信我是唯一一个有这类问题的人。

感谢您的耐心等待。

3 个答案:

答案 0 :(得分:1)

  

创建多线程应用程序,然后添加一个   mutex,根据定义使它只有一个线程可以   一次执行代码?

网络连接涉及计算机处理速度方面的大量等待。这个想法是,大多数时候这些连接将在不同的时间发生,因此不会出现竞争条件,其中两个线程同时尝试修改程序使用的某些数据。但是,两个连接返回的结果很可能在同一时间发生,然后两个线程可能会尝试在同一时间访问程序中的某些数据。为了防止这种情况发生,你可以使用互斥锁,锁等。但是大部分时间都没有等待锁解锁 - 它已经被解锁了。

  

在没有种族的情况下,没有更简单的方法来加速您的代码   条件,例如使用队列

队列是组织工作线程池的好方法。您可以启动一堆从任务队列中读取的线程。因为任务队列最初是空的,所以所有线程都会挂起,等待将某些内容放入队列中。然后你转储一堆任务,例如url,进入任务队列,每个线程从任务队列中检索一个URL,建立连接,然后将结果转储到结果队列中 - 程序从中读取结果休闲。

工作线程在无限循环内从任务队列中检索任务,因此只要它们将结果转储到结果队列中,它们就会返回到循环的顶部并从任务队列中检索另一个任务。在循环内部,您可以编写如下内容:

break if url == "NO_MORE_TASKS"

将所有任务转储到任务队列后,然后将一堆字符串转储到任务队列中,该队列说," NO_MORE_TASKS" - 每个工作线程一个。

将有一个最佳工作线程数,您可以通过尝试不同的数字来发现:5,10,20,40,100,并为您的计划计时。

答案 1 :(得分:1)

你的问题非常笼统 - 作为一个概念性的问题 - 所以我会以同样的方式说出我的答案。

为了正确使用一堆线程来执行一系列类似的任务,你必须安排你的代码,使线程不会与同一个资源进行交互(通常)。

想想你将如何管理一组从事分拣纸张任务的人。如果你只是告诉他们所有人都要对那堆巨大的文件进行排序,你最终会陷入一团糟!但是如果你开始参加一个会议,给每个人递上一套文件并按照他们的排序对他们进行分类,然后当每个人完成后让他们将他们的分类文件交给能够轻松组合两堆分类纸的人,工作可以顺利穿线。

诀窍在于,在开始之前,您需要组织每个线程完成的工作,并在完成后将结果组合起来,但在您工作时,每个工作人员必须在完全围墙的区域中完成工作。

最后将它们组合起来可能会有点麻烦,这就是互斥体会派上用场的部分(因为最后一部分必须由所有不同的线程访问),但“长”的各个部分都已完成那么单线程组合操作不应该花费太多时间。

答案 2 :(得分:1)

从评论开始变得很长。

Mutexes不会保护每个线程中的每个资源,它们只保护您告诉他们保护的资源!如果用互斥锁保护每个资源,那么你的多线程代码运行速度不会比序列化代码快。它们的关键是尽可能少地保护资源并非常简单地保护它们,例如:锁定,写入输出,解锁。这让线程尽可能独立工作。

多线程数据结构(例如队列)仍然在内部使用互斥锁来避免竞争条件 - 它们只是简单的"更简单的"从编码的角度来看,因为它们抽象出锁定/解锁。他们不再具有高性能。话虽这么说,这些结构可以比互斥量更具语义性和使用安全性,因此如果它们满足您的需求,它们应该是首选。

互斥体是线程安全代码的基本构建块 - 只有在您的要求如此简单以至于您不需要任何花哨或复杂以至于需要设计新颖的内容时才使用它们。

互斥体的一个很好的用例是一个共享的全局变量。

require 'thread'
stdout_mutex = Mutex.new

a = Thread.new {
  # run some code that could take a while

  stdout_mutex.synchronize {
    $stdout.puts "Thread A done!"
  }
}

b = Thread.new {
  # run some code that could take while

  stdout_mutex.synchronize {
    $stdout.puts "Thread B done!"
  }
}