我们对线程所做的最酷的事情是什么?

时间:2020-03-06 14:30:26  来源:igfitidea点击:

就是想

解决方案

我对线程所做的最有趣的事情之一是编写一个多线程应用程序来解决迷宫问题。

尽管这没有什么突破性的,但绝对很有趣。

我让它们按我的意愿工作了一次!太酷了!

伊恩·P,介意吗? AFAIK无需使用线程来解决迷宫,除非迷宫如此复杂,以至于等待时间变得无法忍受,我们必须在状态栏中添加内容,以免用户感到无聊并认为程序挂起。

我想说的是,我巧妙地并行化了使用无锁数据结构的算法,以使n核处理器的性能提高n倍。但是我从来没有实际需要,尤其是因为我的大多数专业代码都是针对单核系统的。

几乎每当我使用任何一种语言使用多个线程时,这都是两个原因之一:

  • 系统(或者第三方)提供了阻塞API,而我需要一个异步API(或者至少要一次运行多个操作)。
  • 充分利用基于优先级的抢占式调度,从而使一切保持良好状态和响应能力,而不必将我所有的慢速操作切成小块。

必要的,但不是我们所说的迷人的。

哦-他们不是复杂的迷宫。

迷宫定义在一个数组中,类似于:

String[] MazeArray = new String[5];

MazeArray[0] = "---X---X-------XF";
MazeArray[0] = "-X-X-X---XXXXXXX-";
MazeArray[0] = "-X-X-X-X-X---X---";
MazeArray[0] = "-X-X-X-XXX-X-X-X-";
MazeArray[0] = "SX---X-----X---X-";

当路径中有一个fork时,我会生成一个新的工作线程,并让该线程调查该路径。然后,通过一些基本逻辑,我可以确定最短路径,最长路径等。

列出的示例显然过于简化,但应说明这一点。这是一个有趣的练习,如果我们有几分钟的时间,应该尝试一下。

伊恩

我不知道这是否有意义,但对我来说,一个正在运行的多线程软件本身就很吸引人,与其说它们实现的目的不如说是。程序中有大约10、20、100个工人使用相同的基础结构(Singletons,文件等)工作。使所有事物与互斥体,信号量,上下文切换等协调工作是一件令人愉快的事,就像当经理和团队正在完美地工作一样。我们阅读了应用程序日志,看到线程为了一个共同的目标而合作,这很棒。有人能与这种感觉有关吗?

好吧,这确实是香草,但这是朝着更具创意的穿线方向迈进的不错的垫脚石:

在为我上传新数据和处理类型请求中,请求线程接受数据并将其放入队列中,然后用户继续沿自己的喜好前进。一个或者多个后台线程连续使项目出队并以某种方式处理它们。

我对线程太没用了,我必须让女友重新缝上我的按钮。

我用C ++写了一个小的fcgi servlet模型,该模型为每个新请求立即分配了一个新线程。

如果我们认为这没什么酷的,那么我们应该看看当我通过它进行3K req / s传输时发生了什么。我不小心忘记了清理它们,即使我们全部都自行终止并实际上停止使用内存,它们仍然消耗寻址,并且我让该应用快速重新分配了比我更多的内存,并停止创建线程。

(当时我使用的是32bit,在创建2 ^ 32线程后它实际上停止了。天哪知道使用64bit会做什么)

另外,我为著名的命令rm -rf创建了一个多线程(广度为fork)广度优先的目录上分支。主要是我对rm -rf感到沮丧,因为它似乎在等待IO以yay / nay响应来响应,这使某些目录结构(例如squid缓存)的运行速度变慢。该代码的唯一真正警告是,它仅具有娱乐价值,并且如果曾经在整个文件系统上使用,它将是两种情况之间的竞争:

  • 磁盘被擦除后使其无法使用,并可能擦除了使我们无法运行的命令。
  • 由于"叉式轰炸"速率高,该系统"叉式轰炸"使它的操作强度很高,以至于不再响应命令。

并且在"叉炸弹"的情况下,大量的生成速度可能导致递归rm自身停止(或者达到Ulimit,如果有的话)

我们曾经编写了一个多线程应用程序,该应用程序实际上逐行读取文件,并在内部数据库中进行查找以查看是否存在匹配项,并添加了一些数据并移至下一行。但是,复杂性在于可能同时处理多个文件,并且每个文件可以搜索多个记录。有一个经理类,知道有多少个线程可用,并负责将可用的工作线程划分为每个文件(如果只有一个文件要处理,则它将接收全部40个线程,如果有5个文件,则取决于优先级) ,则每个人都只能收到这40个中的一小部分)。我们最初使用Async委托,但注意到很难捕获异步线程中可能发生的任何异常,因此我们使用.net中的传统线程start。

这样做的关键是在管理器类中有一个ManualResetEvents集合,该类由ManualResentEvents组成,它们是工作器类(线程)中的公共属性。当工作线程完成时,它将指示它是ManualResetEvent,该事件将由Manager类上的.WaitAny()拾取。然后,管理器将知道其中一个线程已完成,并会开始一个新线程。实际上,它比这要复杂一些,但这是其工作的核心。

困难的部分是进行单元测试,以确保在任何给定的时间都在运行正确数量的线程。我们进行了测试,就好像队列中只有一个文件(获取所有40个线程),然后引入了另一个文件,并且对于这两个文件来说,线程的分配必须循环到20个。我们有一个"模拟对象",它实际上具有一个线程睡眠参数,我们将传递一个值(以毫秒为单位),以控制每个线程处理所需的时间,因此我们对何时进行断言或者询问该方法有一个很好的了解。文件处理器查看当前正在处理的线程,记录数。还有一些测试,将两个文件运行在一起,每个线程有20个线程,然后一个文件将完成,并且由于所有记录线程将在第一个文件上完成,因此将它们重新分配给第二个文件,以帮助其更快地完成。

我确信这不是对我们实际所做的最清楚的解释,我真的需要写一篇有关它的博客文章。如果有人需要更多信息,请与我联系,我会尽力回答。

具有异步输入/输出的简单客户端服务器。

最近,我被聘请来帮助在Microsoft Windows系统上运行的具有读取器/写入器锁定对象的相当大且复杂的多线程应用程序。这使得搜索死锁变得困难,因此我编写了一个死锁检测对象,该死锁检测对象在自己的线程中执行,无论何时尝试锁定,成功或者失败,以及锁定和解锁,都会从锁定对象发送信息消息(使用PostThreadMessage)。

通过在真值表中查找不同的线程和共享锁及其状态,可以毫无疑问地查明死锁的原因和位置。

我创建了一个Windows服务来查询大量RSS提要,并将检索到的信息存储在数据库中。由于应用程序可以包含很多RSS提要,因此线程池每隔n次RSS包查询一次。
就像Thorsten79所说的那样,最令人兴奋的部分是观察线程之间的协作和团队合作。

我发现可以只使用一个写入器和一个读取器就可以创建一个FIFO,而无需使用任何同步工具。

(因此具有2 * n FIFO的主从..没有任何互斥锁/信号量!!)

如果链表很长,则不需要同步以在一端插入而在另一端删除。

诀窍是始终在列表中保留一个元素(-;
代码真的很小

当一个硬件人员告诉我..这很明显(-:

我想为dos实现多线程是我使用线程完成的最酷的事情。

我创建了具有无锁任务间通信的线程库,以简化多线程编程。仅限Delphi:OmniThreadLibrary。

(要归功于我没有写无锁结构的原因,GJ做了。)

Web搜寻器的分布式链接检查系统。由于网络抓取是一种非常容易实现线程化的解决方案,所以我不知道这是否值得...

当我上大学时,我确实编写了一种算法来破解DES,该算法是在大学的定制256 CPU机器上运行的。那很整洁,但实际上只是一个分而治之的问题。

我用Java编写了一个使用线程池的图像过滤框架。

令我惊讶的是,即使在单处理器单核计算机上,筛选器在多个并行线程中运行的速度也要快得多。当我找到一些空闲时间时,我想真正找出原因。我要做的就是访问内存和数学计算。

线程摇摆(只要它们不锁定。)

也赞扬Java线程池。

我为HDOS编写了一个多线程库。 HDOS是在HeathKit系统上运行的8位操作系统。我截获了系统时钟滴答声(如果我没记错的话,每55毫秒一次),并且有一个调度程序可以循环方式决定下一个要运行的线程。当然,由于OS本身不是多线程的,因此在任何给定时间仅允许一个线程进入OS。

我从来没有做过任何有用的事情。我决定解决这个有趣的项目,看看我是否可以做到。

我做了一个快速排序的实现,其中分区的左侧和右侧同时进行排序。它仅使用一个线程的速度几乎是同一代码的两倍。

我编写的无锁缓存比最常见的基于锁的缓存库快10倍。弄清楚如何执行复杂的CASing逻辑并提出LRU的替代方案(不会遭受锁定开销)真的很有趣。

我还编写了一个分布式的master-worker框架,后来我对该原型进行了原型设计,以支持fork-join和map-reduce。我需要在某些时候重做这些,因为它们不是生产质量,但这确实很有趣。

我真的很想写一个SkipList数据结构,只是为了学习如何。已经有一个核心实现,但是我很乐意深入研究它,它是一个如此酷而简单的想法。这将纯粹是丢弃代码,但具有教育意义。

这不是多线程的应用程序,而是一个小片段,展示了C3.0功能,包括lambda和对象初始化程序。我可以肯定的是,这不是"我们想的那样",而是"我已经用线程完成的最酷的事情"。

new Thread(() => 
{
    // do stuff in a new thread's context
})
{
    Name = "Thread " + GetHashCode().ToString(),
    Priority = this.threadPriority
}
.Start();

自从我写了多线程是如此的简单以来,我就为C#中的多线程编写了actor / message传递的实现!编写它本身是非常有趣的,用于消息队列的无锁数据结构。没有一个针对每个actor的线程,而是一个线程池,该线程池循环遍历actor并运行每个actor。
由于现在多线程非常简单,因此我可以使用该系统来编写一些很酷的东西:
一个简单的套接字服务器/客户端演示应用程序
多线程网络爬虫(我要回到那个)
游戏的程序内容生成器
和其他一些东西,但是它们都很小而且很无聊