2015-12-15 14 views
6

Tôi vừa mới sử dụng ArrayBlockingQueue cho quy trình đa luồng của mình. Nhưng có vẻ như nó đã chậm lại hơn là tăng tốc. Các bạn có thể giúp tôi không? Tôi cơ bản nhập khẩu một tập tin (khoảng 300k hàng) và phân tích chúng và lưu trữ chúng trong DBSử dụng ArrayBlockingQueue làm cho quy trình chậm hơn

public class CellPool { 
private static class RejectedHandler implements RejectedExecutionHandler { 
    @Override 
    public void rejectedExecution(Runnable arg0, ThreadPoolExecutor arg1) { 
     System.err.println(Thread.currentThread().getName() + " execution rejected: " + arg0);  
    } 
    } 

    private static class Task implements Runnable { 
    private JSONObject obj; 

    public Task(JSONObject obj) { 
     this.obj = obj; 
    } 

    @Override 
    public void run() { 
     try { 
     Thread.sleep(1); 
     runThis(obj); 
     } catch (InterruptedException e) { 
     e.printStackTrace(); 
     } 
    } 

    public void runThis(JSONObject obj) { 
     //where the rows are parsed and stored in the DB, etc 
    } 
    } 

    public static void executeCellPool(String filename) throws InterruptedException { 
    // fixed pool fixed queue 
    BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(300000, true); 
    ThreadPoolExecutor executor = new ThreadPoolExecutor(90, 100, 1, TimeUnit.MINUTES, queue); 

    DataSet ds = CommonDelimitedParser.getDataSet(filename); 
    final String[] colNames = ds.getColumns(); 
    while (ds.next()) { 
     JSONObject obj = new JSONObject(); 
     //some JSON object 
     Task t = new Task(obj); 
     executor.execute(t); 
    } 
    } 

}

+2

Bị chậm lại so với cái gì? Sử dụng một loại 'BlockingQueue' khác? – Andreas

+1

Hãy thoát khỏi giấc ngủ. –

+0

Tại sao? Tôi đề nghị bạn thoát khỏi hàng đợi, các chủ đề, người thi hành, tất cả điều đó và làm tất cả trong một luồng đơn lẻ, dưới dạng một lô. Bạn không cần hàng đợi 30.000 mục và 90-100 chủ đề cho việc này. – EJP

Trả lời

2

Nếu bạn muốn kéo dài kỷ lục từ một tập tin vào một cơ sở dữ liệu quan hệ càng nhanh càng tốt bạn nên sử dụng chèn hàng loạt JDBC thay vì chèn từng bản ghi.

4

tl; dr Kích thước hàng đợi lớn có thể có tác động tiêu cực, vì có thể đếm số lượng lớn. Lý tưởng nhất, bạn muốn người tiêu dùng và nhà sản xuất của bạn hoạt động ở mức tương tự.

Lý do việc thêm hàng đợi gây ra sự cố là vì bạn đang sử dụng hàng đợi rất lớn (không cần thiết) đang chiếm dụng tài nguyên. Thông thường, một hàng đợi ngăn chặn các nhà sản xuất khi không có không gian còn lại trong hàng đợi và người tiêu dùng khi không có đối tượng nào còn lại trong hàng đợi. Bằng cách tạo một kích thước lớn như vậy với kích thước tĩnh, Java chỉ định không gian đó trong bộ nhớ khi bạn gần như chắc chắn không sử dụng tất cả. Sẽ có hiệu quả hơn khi buộc nhà sản xuất của bạn chờ đợi không gian trong hàng đợi để làm sáng tỏ nếu người tiêu dùng của bạn là người tiêu dùng quá chậm. Bạn không cần phải lưu trữ tất cả các dòng từ tập tin của bạn trong hàng đợi cùng một lúc.

Chủ đề Hồ bơi Hàng đợi của công nhân viên được thảo luận trong javadoc here.

Hàng đợi bị chặn. Một hàng đợi bị chặn (ví dụ, một ArrayBlockingQueue) giúp ngăn chặn cạn kiệt tài nguyên khi được sử dụng với tối đa hóa tối đaPoolSizes, nhưng có thể khó điều chỉnh và kiểm soát hơn. Kích thước hàng đợi và kích thước hồ bơi tối đa có thể được giao dịch cho nhau: Sử dụng hàng đợi lớn và các bể nhỏ giảm thiểu việc sử dụng CPU, tài nguyên hệ điều hành và phí chuyển đổi ngữ cảnh, nhưng có thể dẫn đến thông lượng giả tạo thấp. Nếu các tác vụ thường xuyên chặn (ví dụ nếu chúng là I/O bị ràng buộc), một hệ thống có thể lên lịch thời gian cho nhiều luồng hơn bạn cho phép. Sử dụng hàng đợi nhỏ thường yêu cầu kích thước hồ bơi lớn hơn, giúp CPU bận rộn hơn nhưng có thể gặp phải chi phí lên lịch không được chấp nhận, điều này cũng làm giảm thông lượng.

Kích thước chủ đề lớn là 90, kết hợp với kích thước hồ bơi rất lớn 300000, rất có thể sử dụng nhiều bộ nhớ và dẫn đến thêm chi phí lên lịch. Tôi sẽ thả cả hai chúng một cách đáng kể. Tôi không biết bạn đang chạy phần cứng nào, nhưng có vẻ như bạn đang viết một chương trình chuyên sâu IO, tôi sẽ thử gấp đôi số lượng chủ đề mà CPU của bạn có thể xử lý và chơi với kích thước cho hàng đợi chặn của bạn những gì làm việc (lưu ý: Tôi đã không nghiên cứu này, điều này được dựa trên kinh nghiệm của tôi chạy hàng đợi và thực thi. Chúc mừng những người khác để đề xuất một số khác nhau!).

Lưu ý, mặc dù, là phương pháp execute() sẽ ném một số RejectedExecutionException do không thêm vào hàng đợi nếu hàng đợi của bạn quá nhỏ. Một cách để theo dõi hàng đợi là kiểm tra dung lượng của nó trước khi lên lịch một nhiệm vụ. Bạn có thể thực hiện việc này bằng cách gọi:

executor.getQueue().remainingCapacity() 

Không sử dụng phương thức executor.getQueue() để thay đổi hàng đợi theo bất kỳ cách nào nhưng có thể được sử dụng để theo dõi.

Cách khác là sử dụng hàng đợi không bị chặn, chẳng hạn như LinkedBlockingQueue mà không có dung lượng được xác định. Bằng cách này, bạn sẽ không cần phải xử lý kích thước hàng đợi.Tuy nhiên, nếu các nhà sản xuất của bạn đang chạy nhanh hơn nhiều so với người tiêu dùng của bạn, bạn lại một lần nữa sẽ có vấn đề tiêu thụ quá nhiều bộ nhớ.

Ngoài ra, kostya là đúng, chèn hàng loạt JDBC sẽ nhanh hơn.

+0

Cảm ơn, AndyN và @kostya vì điều này! Tôi khá mới trong java. Tôi đã thử chèn hàng loạt, nó nhanh hơn đáng kể. :) – Kara

Các vấn đề liên quan