Lua - Coroutines

Giới thiệu

Coroutines về bản chất là hợp tác, cho phép hai hoặc nhiều phương pháp thực thi một cách có kiểm soát. Với coroutines, tại bất kỳ thời điểm nào, chỉ có một quy trình đăng ký chạy và quy trình đăng ký đang chạy này chỉ tạm ngừng thực thi khi nó yêu cầu tạm dừng một cách rõ ràng.

Định nghĩa trên có thể trông mơ hồ. Giả sử chúng ta có hai phương thức, một phương thức chương trình chính và một phương thức đăng quang. Khi chúng ta gọi một trình điều chỉnh bằng cách sử dụng hàm tiếp tục, nó bắt đầu thực thi và khi chúng ta gọi hàm lợi nhuận, nó sẽ tạm ngừng thực thi. Một lần nữa, cùng một quy trình đăng ký có thể tiếp tục thực hiện với một lệnh gọi hàm tiếp tục khác từ nơi nó bị tạm dừng. Quá trình này có thể tiếp tục cho đến khi kết thúc quá trình điều tra.

Các chức năng có sẵn trong Coroutines

Bảng sau liệt kê tất cả các hàm có sẵn cho các coroutines trong Lua và cách sử dụng tương ứng của chúng.

Sr.No. Phương pháp & Mục đích
1

coroutine.create (f)

Tạo một chương trình đăng quang mới với hàm f và trả về một đối tượng kiểu "thread".

2

coroutine.resume (co [, val1, ...])

Tiếp tục đồng hành trình đăng quang và chuyển các tham số nếu có. Nó trả về trạng thái hoạt động và các giá trị trả về tùy chọn khác.

3

coroutine.running ()

Trả về quy trình đăng quang hoặc nil đang chạy nếu được gọi trong luồng chính.

4

coroutine.status (co)

Trả về một trong các giá trị đang chạy, bình thường, bị treo hoặc chết dựa trên trạng thái của quy trình đăng ký.

5

coroutine.wrap (f)

Giống như coroutine.create, hàm coroutine.wrap cũng tạo ra một coroutine, nhưng thay vì trả về chính hàm coroutine, nó trả về một hàm mà khi được gọi, sẽ tiếp tục lại hàm coroutine.

6

coroutine.yield (...)

Tạm dừng quy trình đăng ký đang chạy. Tham số được truyền cho phương thức này hoạt động như các giá trị trả về bổ sung cho hàm tiếp tục.

Thí dụ

Hãy xem một ví dụ để hiểu khái niệm về coroutines.

co = coroutine.create(function (value1,value2)
   local tempvar3 = 10
   print("coroutine section 1", value1, value2, tempvar3)
	
   local tempvar1 = coroutine.yield(value1+1,value2+1)
   tempvar3 = tempvar3 + value1
   print("coroutine section 2",tempvar1 ,tempvar2, tempvar3)
	
   local tempvar1, tempvar2= coroutine.yield(value1+value2, value1-value2)
   tempvar3 = tempvar3 + value1
   print("coroutine section 3",tempvar1,tempvar2, tempvar3)
   return value2, "end"
	
end)

print("main", coroutine.resume(co, 3, 2))
print("main", coroutine.resume(co, 12,14))
print("main", coroutine.resume(co, 5, 6))
print("main", coroutine.resume(co, 10, 20))

Khi chúng ta chạy chương trình trên, chúng ta sẽ nhận được kết quả sau.

coroutine section 1	3	2	10
main	true	4	3
coroutine section 2	12	nil	13
main	true	5	1
coroutine section 3	5	6	16
main	true	2	end
main	false	cannot resume dead coroutine

Ví dụ trên làm gì?

Như đã đề cập trước đây, chúng tôi sử dụng chức năng tiếp tục để bắt đầu hoạt động và chức năng lợi nhuận để dừng hoạt động. Ngoài ra, bạn có thể thấy rằng có nhiều giá trị trả về nhận được bởi hàm tiếp tục của coroutine.

  • Đầu tiên, chúng ta tạo một chương trình đăng quang và gán nó cho một tên biến và chương trình đăng quang nhận hai biến làm tham số của nó.

  • Khi chúng ta gọi hàm tiếp tục đầu tiên, các giá trị 3 và 2 được giữ lại trong các biến tạm thời value1 và value2 cho đến cuối chương trình đăng quang.

  • Để bạn hiểu điều này, chúng tôi đã sử dụng tempvar3, ban đầu là 10 và nó được cập nhật lên 13 và 16 bởi các lệnh gọi tiếp theo của coroutines vì ​​value1 được giữ lại là 3 trong suốt quá trình thực thi coroutine.

  • Coroutine.yield đầu tiên trả về hai giá trị 4 và 3 cho hàm tiếp tục, chúng tôi nhận được giá trị này bằng cách cập nhật các tham số đầu vào 3 và 2 trong câu lệnh lợi nhuận. Nó cũng nhận được trạng thái true / false của quá trình thực thi coroutine.

  • Một điều khác về coroutines là cách xử lý các thông số tiếp theo của cuộc gọi sơ yếu lý lịch, trong ví dụ trên; bạn có thể thấy rằng biến coroutine.yield nhận các tham số cuộc gọi tiếp theo, cung cấp một cách mạnh mẽ để thực hiện hoạt động mới với việc kiểm tra lại các giá trị tham số hiện có.

  • Cuối cùng, một khi tất cả các câu lệnh trong coroutines được thực thi, các lệnh gọi tiếp theo sẽ trả về false và câu lệnh "không thể tiếp tục coroutine đã chết" dưới dạng phản hồi.

Một ví dụ về thói quen khác

Chúng ta hãy xem xét một quy trình đăng quang đơn giản trả về một số từ 1 đến 5 với sự trợ giúp của hàm lợi nhuận và hàm tiếp tục. Nó tạo ra quy trình đăng ký nếu không có sẵn hoặc nếu không sẽ tiếp tục quy trình đăng ký hiện có.

function getNumber()
   local function getNumberHelper()
      co = coroutine.create(function ()
      coroutine.yield(1)
      coroutine.yield(2)
      coroutine.yield(3)
      coroutine.yield(4)
      coroutine.yield(5)
      end)
      return co
   end
	
   if(numberHelper) then
      status, number = coroutine.resume(numberHelper);
		
      if coroutine.status(numberHelper) == "dead" then
         numberHelper = getNumberHelper()
         status, number = coroutine.resume(numberHelper);
      end
		
      return number
   else
      numberHelper = getNumberHelper()
      status, number = coroutine.resume(numberHelper);
      return number
   end
	
end

for index = 1, 10 do
   print(index, getNumber())
end

Khi chúng ta chạy chương trình trên, chúng ta sẽ nhận được kết quả sau.

1	1
2	2
3	3
4	4
5	5
6	1
7	2
8	3
9	4
10	5

Thường có sự so sánh các coroutines với các thread của ngôn ngữ đa chương trình, nhưng chúng ta cần hiểu rằng coroutines có các tính năng tương tự của thread nhưng chúng chỉ thực thi một lần và không bao giờ thực thi đồng thời.

Chúng tôi kiểm soát trình tự thực hiện chương trình để đáp ứng nhu cầu với việc cung cấp tạm thời giữ lại một số thông tin nhất định. Sử dụng các biến toàn cục với coroutines cung cấp tính linh hoạt hơn nữa cho coroutines.