2011-11-16 58 views
4

您将如何测试具有一些并发功能的Ruby代码?例如,让我们假设我有一个预计可以防止死锁的同步机制。有没有一种可行的方法来测试它的真正作用?可以控制纤维的执行是前进的方向吗?测试并发特性

+0

即使在社区比Ruby社区更注重并发性的语言中,这仍是一个难题。 http://stackoverflow.com/questions/12159/how-should-i-unit-test-threaded-code –

+0

任何机会,你可以发布一些代码,甚至伪代码E?这很难一般地回答,并且很难知道您希望测试的代码的哪些方面。 – davetron5000

回答

1

我需要确保我编写的gem(redis-native_hash)可以处理对同一个Redis散列的并发写入,检测竞争条件并优雅地恢复。我发现为了测试这个,我根本不需要使用线程。

it "should respect changes made since last read from redis" do 
    concurrent_edit = Redis::NativeHash.find :test => @hash.key 
    concurrent_edit["foo"] = "race value" 
    concurrent_edit.save 
    @hash["yin"] = "yang" 
    @hash["foo"] = "bad value" 
    @hash.save 
    hash = Redis::NativeHash.find :test => @hash.key 
    hash["foo"].should == "race value" 
    hash["yin"].should == "yang" 
end 

在此测试情况下,我刚才实例代表Redis的哈希值的同时编辑另一个对象,有它做出改变,然后确定保存指向相同的散列已经存在的对象尊重这些变化。

并非所有涉及并发的问题都可以在没有使用并发性的情况下进行测试,但在这种情况下是可行的。您可能想尝试寻找类似的东西来测试您的并发解决方案。如果可能的话,它肯定是更容易的路线。

+0

我明白你的观点。对于特定情况,这是一个优雅的解决方法。 – PJK

1

记录为Rails3中先进的使用场景这绝对是一个棘手的问题。我开始使用线程编写我的测试,并意识到他们的方式我测试的代码已经实现,我需要进程ID(PID)实际上是不同的。线程使用与启动线程的进程相同的PID运行。学过的知识。

就在那时,我开始探索叉子,并遇到了这个堆栈溢出线程,并与fork_break一起玩。非常酷,并且易于设置。尽管我不需要为我所做的工作提供断点,但我只是想让进程同时运行,使用断点在未来可能会非常有用。我遇到的问题是我不断收到EOFError,我不知道为什么。所以我开始实现自己的分叉,而不是通过fork_break,并发现在被测代码中发生异常。可悲的是堆栈跟踪由EOFError对我隐藏,虽然我明白,子进程突然结束,这是怎么回事。

我遇到的下一个问题是DatabaseCleaner。不管使用哪种策略(截断或事务),子进程的数据在子进程完成时被截断/回滚,因此子进程插入的数据消失了,父​​进程无法选择并验证它是正确的。

在我的脑海里敲了一下,并尝试了许多其他不成功的东西之后,我碰到了这个帖子http://makandracards.com/makandra/556-test-concurrent-ruby-code,这几乎就是我已经在做的事情,只有一点点补充。调用“Process.exit!”在叉子的尽头。我最好的猜测(基于我对分叉的相当有限的理解)是,这会导致进程突然结束,以至于当子进程结束时它完全绕过任何类型的数据库清理。所以我的父进程,实际测试,可以继续并验证它需要验证的数据。然后,在正常的测试挂钩(在本例中为黄瓜,但也可以很容易地rspec)期间,数据库清理器会像通常进行测试一样启动并清理数据。

所以,只是想我会分享一些我自己的经验教训,在这个讨论如何测试并发功能。