2009-05-18 110 views
2
class ApplicationContext{ 
    private final NetworkObject networkObject = new networkObject(); 

    public ApplicationContext(){ 
     networkObject.setHost("host"); 
     networkObject.setParams("param"); 
    } 

    public searchObjects(ObjectType objType){ 
     networkObject.doSearch(buildQuery(objType)); 
    } 
} 

class NetworkObject{ 
    private final SearchObject searchObject = new SearchObject(); 

    public doSearch(SearchQuery searchQuery){ 
     searchObject.search(searchQuery); //threadsafe, takes 15(s) to return 
    } 
} 

考虑一个运行web应用程序的web服务器,该应用程序只创建一个ApplicationContext实例(单例)并使用相同的applicationInstance来调用searchObjects例如为什么多线程似乎不能加速我的web应用程序?

ApplicationContext appInstance = 
        ApplicationContextFactory.Instance(); //singleton 

到网页上每一个新的请求,说 'search.jsp的' 发出呼叫

appInstance.searchObjects(objectType); 

我提出1000个请求为“search.jsp的页面。所有线程都使用相同的ApplicationContext实例,而searchObject.search()方法需要15秒才能返回。我的问题是当所有其他线程执行searchObject.search()函数或所有线程同时执行searchObject.search()时等待轮到他们(15秒)执行,为什么?

我希望我已经提出了我的问题非常清楚??

更新: 谢谢所有澄清我的疑问。这里是我的第二个问题,当我这样做应该遵守的性能有什么区别:

public synchronized doSearch(SearchQuery searchQuery){ 
    searchObject.search(searchQuery); //threadsafe, takes 15(s) to return 
} 

OR

public doSearch(SearchQuery searchQuery){ 
    searchObject.search(searchQuery); //threadsafe, takes 15(s) to return 
} 

我相信使用功能“doSearch”没有synchronized关键字,应给予更多的性能。但是,当我今天进行测试时,结果是以另一种方式出现的。当我使用同步关键字时,性能相似或有时更好。

任何人都可以解释行为。我应该如何调试这种情况。

问候,

佩里

回答

5

那么你有没有指定任何同步代码,所以没有任何其他证据我怀疑,所有的线程将同时运行。如果SearchObject.search尽管包含一些同步,那么显然会限制并发性。

请注意,您的JSP容器可能使用线程池来处理1000个请求,而不是创建1000个线程。

编辑:至于为什么它可能会更快​​:有时并发实际上并不有助于吞吐量。诸如上下文切换,磁盘瓶颈,缓存未命中等等都会产生这种影响。这是通常不是一个好主意有更多的运行线程比核心。

对于一个真实的例子,假设你有一千个购物者都想从一个相当小的商店买东西。你会怎么做呢?同时将所有1000件商品放在商店中,或在任何时间将商店中的商品数量保持在相当小的数量,并在外面排队?

+0

请看我上面的更新! – pankajt 2009-05-18 14:41:47

0

就你而言,它们将全部同时执行。

如果您想防止这种情况发生,您需要进行某种同步以防止这种情况发生(例如将该方法声明为已同步或使用锁定)。

ETA:

如果声明doSearch()方法同步,只有一次一个线程就可以调用它。其他线程将阻塞,直到第一个线程结束,等待的线程将一次一个“放入”。正如你可以想象的,如果你有很多线程调用这个函数,这会杀死你的性能。

+0

请看我上面的更新! – pankajt 2009-05-18 14:42:05

0

如果你没有同步,那么每个线程将同时运行,而不是锁定在锁上。

注意

// threadsafe 

(如注释)意味着它会与多个线程访问它正常工作 - ,它会阻塞线程。

+0

请看我上面的更新! – pankajt 2009-05-18 14:42:09

0

它们都可以同时执行它,除非它被声明为同步,无论您的班级是单身人士IIRC。

+0

请看我上面的更新! – pankajt 2009-05-18 14:42:13

0

如果SearchObject.search是同步的,那么是的。否则,试试看看。

+0

请看我上面的更新! – pankajt 2009-05-18 14:42:17

0

为什么需要15秒?如果它正在等待磁盘访问并且只有一个磁盘,那么无论您有多少线程受到磁盘搜索速度的限制。在这种情况下,更多的线程可能会更慢。

+0

我同意,如果所有线程都在等待磁盘访问,性能会变慢。我想知道同步如何影响这里的性能,假设search()方法需要很短的时间返回 – pankajt 2009-05-18 15:17:08

1

认识到性能与特定环境相关是明智的。在这种情况下,它可能是您的笔记本电脑或测试服务器上的软件性能。在考虑优化代码之前,检查与生产环境相似的性能是明智的,因为它们的瓶颈可能与开发机器上的瓶颈有很大不同。

作为一个例子;当我用笔记本电脑上的大型数据库测试我的软件时,我总是被硬盘IO绑定。但在生产中,数据库服务器拥有大量内存和快速磁盘,因此优化我的IO软件不是明智之举。

与线程类似;我的笔记本电脑中的处理器可以同时运行一个或两个进程。拥有8个线程不会加快速度。然而,生产机器可能能够同时处理8个螺纹。

我认为比性能更重要的是语义。使用像同步这样的关键字不仅对编译器有用,而且对(下一个)开发者也有用。

通过使用同步,您可以与ApplicationContext上的所有其他同步方法共享锁,也可以与searchObject无关。 就我个人而言,我非常怀疑您希望在名为ApplicationContext的对象上进行同步。

如果searchObject不是线程安全的,我可能会推荐一个锁定对象。这倒还口味:

public void doSearch(SearchQuery searchQuery){ 
    synchronized(searchObject) {// Only if searchObject is guaranteed to be null 
     searchObject.search(searchQuery); //threadsafe, takes 15(s) to return 
    } 
} 

public class ApplicationContext { 
    private SearchObject searchObject = null; 
    private final Object searchObjectLock = new Object();  

    public void doSearch(SearchQuery searchQuery){ 
     synchronized(searchObjectLock) { 
      searchObject.search(searchQuery); //threadsafe, takes 15(s) to return 
     } 
    } 
} 

不要忘了锁每次使用searchObject,防止螺纹麻烦。使用这种细粒度的锁定机制,您至少可以将ApplicationContext保留为不需要searchObject相关功能的类。

在你的情况下,我不会使用任何同步,因为它不是必需的,并且在确定瓶颈之前检查类似生产的硬件。

如果searchObject使用数据库,请确保数据库属性已编入索引并使用该索引。如果需要做1000次全表扫描,它不会很快...

+0

我同意性能是用硬件调整的。但作为一般规则或原则,我们确实遵循了某些准则。我同意Jon关于线程数等于核心数 – pankajt 2009-05-18 20:02:27

相关问题