AsyncTask sử dụng mẫu nhóm luồng để chạy nội dung từ doInBackground (). Vấn đề ban đầu (trong các phiên bản HĐH Android đầu tiên) kích thước nhóm chỉ là 1, nghĩa là không có tính toán song song cho một loạt các AsyncT Nhiệm vụ. Nhưng sau đó họ đã sửa nó và bây giờ kích thước là 5, vì vậy nhiều nhất là 5 AsyncT task có thể chạy đồng thời. Thật không may, tôi không nhớ chính xác phiên bản nào họ đã thay đổi điều đó.
CẬP NHẬT:
Đây là những gì API hiện tại (2012-01-27) nói về điều này:
Khi được giới thiệu lần đầu tiên, AsyncT task đã được thực thi ser seri trên một luồng nền đơn. Bắt đầu với DONUT, điều này đã được thay đổi thành một nhóm các luồng cho phép nhiều tác vụ hoạt động song song. Sau HONEYCOMB, nó được lên kế hoạch để thay đổi điều này trở lại thành một luồng duy nhất để tránh các lỗi ứng dụng phổ biến do thực thi song song. Nếu bạn thực sự muốn thực thi song song, bạn có thể sử dụng phiên bản execOnExecutor (Executor, Params ...) của phương thức này với THREAD_POOL_EXECUTOR; tuy nhiên, xem bình luận ở đó để cảnh báo về việc sử dụng nó.
DONUT là Android 1.6, HONEYCOMB là Android 3.0.
CẬP NHẬT: 2
Xem bình luận của kabuko
từ Mar 7 2012 at 1:27
.
Nó chỉ ra rằng đối với các API trong đó "một nhóm các luồng cho phép nhiều tác vụ hoạt động song song" được sử dụng (bắt đầu từ 1.6 và kết thúc vào 3.0), số lượng AsyncT task chạy đồng thời phụ thuộc vào số lượng tác vụ đã được chuyển để thực thi, nhưng chưa hoàn thành của họ doInBackground()
được nêu ra.
Điều này đã được thử nghiệm / xác nhận bởi tôi vào ngày 2.2. Giả sử bạn có một AsyncTask tùy chỉnh chỉ cần ngủ một giây doInBackground()
. AsyncT task sử dụng hàng đợi kích thước cố định trong nội bộ để lưu trữ các tác vụ bị trì hoãn. Kích thước hàng đợi là 10 theo mặc định. Nếu bạn bắt đầu 15 tác vụ tùy chỉnh của mình liên tiếp, thì 5 đầu tiên sẽ nhập chúng doInBackground()
, nhưng phần còn lại sẽ đợi trong hàng đợi cho một luồng công nhân miễn phí. Ngay khi bất kỳ trong số 5 kết thúc đầu tiên kết thúc và do đó giải phóng một luồng công nhân, một tác vụ từ hàng đợi sẽ bắt đầu thực thi. Vì vậy, trong trường hợp này, tối đa 5 nhiệm vụ sẽ chạy đồng thời. Tuy nhiên, nếu bạn bắt đầu 16 tác vụ tùy chỉnh liên tiếp, thì 5 đầu tiên sẽ nhập chúng doInBackground()
, 10 phần còn lại sẽ vào hàng đợi, nhưng trong lần thứ 16, một luồng công nhân mới sẽ được tạo để nó bắt đầu thực thi ngay lập tức. Vì vậy, trong trường hợp này, nhiều nhất là 6 nhiệm vụ sẽ chạy đồng thời.
Có giới hạn về số lượng tác vụ có thể được chạy đồng thời. Do AsyncTask
sử dụng bộ thực thi nhóm luồng với số lượng luồng công nhân tối đa hạn chế (128) và hàng đợi tác vụ bị trì hoãn có kích thước 10 cố định, nếu bạn cố thực hiện hơn 138 tác vụ tùy chỉnh của mình, ứng dụng sẽ gặp sự cố java.util.concurrent.RejectedExecutionException
.
Bắt đầu từ 3.0, API cho phép sử dụng trình thực thi nhóm luồng tùy chỉnh của bạn thông qua AsyncTask.executeOnExecutor(Executor exec, Params... params)
phương thức. Ví dụ, điều này cho phép định cấu hình kích thước của hàng đợi tác vụ bị trì hoãn nếu mặc định 10 không phải là thứ bạn cần.
Như @Knossos đề cập, có một tùy chọn để sử dụng AsyncTaskCompat.executeParallel(task, params);
từ thư viện v.4 hỗ trợ để chạy các tác vụ song song mà không bận tâm đến mức API. Phương pháp này trở nên không dùng nữa trong API cấp 26.0.0.
CẬP NHẬT: 3
Đây là một ứng dụng thử nghiệm đơn giản để chơi với số lượng tác vụ, thực hiện nối tiếp so với thực thi song song: https://github.com/vitkhudenko/test_asynctask
CẬP NHẬT: 4 (cảm ơn @penkzhou đã chỉ ra điều này)
Bắt đầu từ Android 4.4 AsyncTask
hoạt động khác với những gì được mô tả trong phần CẬP NHẬT: 2 . Có một sửa chữa để ngăn chặn AsyncTask
quá nhiều chủ đề.
Trước Android 4.4 (API 19) AsyncTask
đã có các trường sau:
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
Trong Android 4.4 (API 19), các trường trên được thay đổi thành:
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
Thay đổi này làm tăng kích thước của hàng đợi lên 128 mục và giảm số lượng luồng tối đa xuống số lõi CPU * 2 + 1. Ứng dụng vẫn có thể gửi cùng số lượng tác vụ.