0
0
Lập trình
Harry Tran
Harry Tran106580903228332612117

Hiểu Rõ Về Đồng Thời và Tính Song Song Trong Clprolf

Đăng vào 7 tháng trước

• 8 phút đọc

Clprolf Docs #5 — Hiểu Rõ Về Đồng Thời và Tính Song Song

Giới thiệu

Trong loạt tài liệu chính thức về Clprolf, bài viết này (phần 5 trong 6) sẽ giúp bạn hiểu rõ hơn về đồng thời và tính song song trong ngôn ngữ lập trình Clprolf. Clprolf không chỉ là một ngôn ngữ mới mà còn là một framework hỗ trợ lập trình hướng đối tượng (OOP) một cách rõ ràng hơn bằng cách áp dụng các vai trò, trách nhiệm và thiết kế sạch.

Các Hỗ Trợ Cho Đồng Thời và Tính Song Song Trong Clprolf

Clprolf giới thiệu một loạt các hỗ trợ ngữ nghĩa nhằm giúp việc đồng thời và tính song song trở nên dễ hiểu hơn và an toàn hơn khi triển khai. Các hỗ trợ này không nhằm thay thế các cấu trúc mạnh mẽ của Java, mà để làm rõ mục đích và đưa chúng lại gần hơn với phương pháp thiết kế rõ ràng của Clprolf.

Chúng chủ yếu áp dụng cho các tác nhân (agents), nhưng cũng có thể áp dụng cho các tác nhân công việc (worker agents), đảm bảo rằng cả mô phỏng thực tế và các thành phần kỹ thuật đều có thể được hưởng lợi.


Hỗ Trợ Đồng Thời

Clprolf cung cấp hai modifier:

  • long_action (@Long_action)
  • prevent_missing_collision (@Prevent_missing_collision)

Những modifier này giúp làm rõ cách xử lý các hành động mất thời gian và đảm bảo rằng các tương tác quan trọng (như va chạm) không bao giờ bị bỏ lỡ.


Modifier long_action

Một số phương thức trong một tác nhân đại diện cho các hành động mất thời gian, không chỉ là các thay đổi trạng thái ngay lập tức.
Ví dụ: trong một trò chơi điện tử, phương thức Player.jump() là một hành động dài — nhân vật sẽ nhảy lên, rơi xuống và hạ cánh.

Chúng ta không muốn quản lý từng bước một cách thủ công; chúng ta chỉ muốn kích hoạt hành động. Clprolf chia hành động thành các bước, tự động thực hiện cho đến khi hoàn thành.


Modifier prevent_missing_collision

Các va chạm có thể bị bỏ lỡ nếu hai thực thể di chuyển cùng lúc và đi xuyên qua nhau. Để tránh điều này, các phương thức cập nhật vị trí được đánh dấu với prevent_missing_collision.

Điều này đảm bảo rằng kiểm tra va chạm được thực hiện trước khi chuyển động được áp dụng.


Hỗ Trợ Tính Song Song

Clprolf bổ sung cho các cấu trúc của Java với ba modifier cho việc thực thi song song:

  • one_at_a_time (@One_at_a_time)
  • turn_monitor (@Turn_monitor)
  • for_every_thread (@For_every_thread)

Những modifier này không thay đổi cơ chế bên dưới, nhưng làm cho việc đa luồng trở nên rõ ràng và dễ đọc hơn.


Modifier one_at_a_time

Đánh dấu một phương thức là đồng bộ.
Điều này làm rõ rằng chỉ có một luồng tại một thời điểm có thể thực thi phương thức này, tạo cảm giác như ứng dụng đang chạy một luồng cho các phần quan trọng.


Modifier turn_monitor

Điều phối nhiều phương thức one_at_a_time giữa các lớp khác nhau. Trường được đánh dấu đại diện cho đối tượng khóa được chia sẻ bởi các phương thức này.

Ví dụ: Player.place()Enemy.place() có thể sử dụng cùng một @Turn_monitor, đảm bảo rằng các phần quan trọng của chúng hoạt động như một chuỗi đơn luồng.


Modifier for_every_thread

Đánh dấu một trường là volatile (hoặc tương đương).
Điều này đảm bảo rằng giá trị mới nhất được nhìn thấy qua các luồng, tránh các vấn đề liên quan đến bộ nhớ đệm. Điều này làm cho tính an toàn đồng thời trở nên rõ ràng ngay lập tức trong mã nguồn.


Các Hoạt Động Phụ Thuộc

Một số hoạt động không thể tiếp tục cho đến khi một hoạt động khác hoàn thành. Clprolf thể hiện điều này với dependent_activity (@Dependent_activity).

Ví dụ: một hộp thư với một khe tin nhắn.

  • read() phải chờ cho đến khi write() đã đặt một tin nhắn.
  • write() phải chờ cho đến khi hộp thư trống.

Cả hai đều được đánh dấu là @Dependent_activity và chia sẻ cùng một @Turn_monitor. Điều này mô phỏng mô hình nhà sản xuất/nhà tiêu thụ mà không cần phải sử dụng thuật ngữ kỹ thuật.


Khuyến Nghị Thiết Kế

  • Bắt đầu đơn giản: viết mã đơn luồng trước, sử dụng long_actionprevent_missing_collision.
  • Thêm tính song song khi cần: áp dụng one_at_a_time, turn_monitor, và for_every_thread chỉ khi thực sự cần đa luồng.
  • Sử dụng các hoạt động phụ thuộc: chúng làm cho các phụ thuộc giữa các luồng trở nên rõ ràng và giảm độ phức tạp trong suy nghĩ.

Các Cân Nhắc Về Hiệu Suất

  • Những modifier này là các hỗ trợ ngữ nghĩa — chúng dựa vào các cấu trúc Java (synchronized, volatile, wait, notifyAll).
  • Không có chi phí hiệu suất nào được giới thiệu so với mã Java tương đương.
  • Chúng chỉ đơn giản làm cho ý định thiết kế trở nên rõ ràng và nhất quán.

Ví Dụ Mã

Ví Dụ Tác Nhân: Player với long_actionprevent_missing_collision

java Copy
public simu_real_obj Player {
    @Long_action
    private boolean isFalling = false;

    public prevent_missing_collision void place(int xWanted, int yWanted, MovementKind kindWantedMvt) {
        if (isSettingUpLadder && checkPlayerInLadder()==null) {
            this.isSettingUpLadder = false;
        }
        if (!checkIfInEnemyPosition(xWanted, yWanted)) {
            this.x = xWanted;
            this.y = yWanted;
        }
    }

    public long_action void fallIfHole() {
        if (!this.isFalling && !isJumping && !isSettingUpLadder && !checkIfNoPlatformBehind()) {
            this.isFalling = true;
            this.continueFallIfHole();
        }
    }

    public long_action void continueFallIfHole() {
        if (this.isFalling && !this.isSettingUpLadder) {
            if (!isJumping && !checkIfNoPlatformBehind()) {
                this.place(x, y+1, true);
            } else {
                this.isFalling = false;
            }
        }
    }

    public long_action void endLongActions() {
        if (this.game.realiz.waitPaintCount(2)) {
            continueJump();
        }
        if (this.game.realiz.waitPaintCount(2)) {
            continueFallIfHole();
        }
    }
}

Ví Dụ Tác Nhân Công Việc: OneMessageMailBox với Các Hoạt Động Phụ Thuộc

java Copy
/* Một lớp với hai hoạt động phụ thuộc */
@Abstraction
public class OneMessageMailBox {

    private String message;

    @For_every_thread
    private boolean full; // Không volatile ở đây, vì được sử dụng trong một khối đồng bộ

    @Turn_monitor
    private Object mailBoxMonitor; // Đối tượng khóa chia sẻ, cũng được sử dụng cho wait()/notify()

    public OneMessageMailBox() {
        mailBoxMonitor = new Object();
    }

    @Dependent_activity
    @One_at_a_time
    public String read() {
        synchronized(mailBoxMonitor) {
            while (!this.full) {
                try {
                    this.mailBoxMonitor.wait();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            this.full = false;
            this.mailBoxMonitor.notifyAll();
            return this.message;
        }
    }

    @Dependent_activity
    @One_at_a_time
    public void write(String message) {
        synchronized(mailBoxMonitor) {
            while (this.full) {
                try {
                    this.mailBoxMonitor.wait();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            this.message = message;
            this.full = true;
            this.mailBoxMonitor.notifyAll();
        }
    }
}

Kết Luận

Đồng thời và tính song song vốn phức tạp. Clprolf không cố gắng giấu đi sự phức tạp này, mà thay vào đó cung cấp các công cụ rõ ràng và cụ thể:

  • long_actionprevent_missing_collision cho đồng thời,
  • one_at_a_time, turn_monitor, và for_every_thread cho tính song song,
  • dependent_activity để làm rõ các phụ thuộc giữa các luồng.

Với những hỗ trợ này, mã nguồn giữ được sự đơn giản, cấu trúc rõ ràng và gần gũi với lý luận thực tế. Clprolf khuyến khích các lập trình viên nghĩ trước tiên theo phương thức đồng thời đơn luồng, và chỉ sau đó mở rộng sang đa luồng khi cần thiết.


Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào