2008-12-12 40 views
6

Vòng lặp chặt chẽ trong chương trình có tệ không?Vòng lặp có bị hỏng không?

Tôi có một ứng dụng có hai luồng cho trình mô phỏng trò chơi-vật lý. Chủ đề updateGame và chuỗi hiển thị. Chuỗi hiển thị được điều chỉnh bằng cách khiến cho luồng ngủ mất vài mili giây (để đạt được tốc độ khung hình tôi muốn) và chuỗi updateGame (cập nhật vị trí đối tượng trò chơi của tôi dựa trên một số phương trình vật lý) trước đây đã được điều chỉnh bởi giấc ngủ 10 phần nghìn giây .

Tuy nhiên, gần đây tôi đã không cập nhật bản cập nhậtGame chủ đề và mô phỏng chuyển động của đối tượng của tôi có vẻ thực tế hơn đáng kể khi tôi đã lấy ra 10ms ngủ. Là nó xấu đến vòng lặp nóng hoặc có một vòng lặp chặt chẽ?

private class UpdateTask implements Runnable 
{ 
    private long previousTime = System.currentTimeMillis(); 
    private long currentTime = previousTime; 
    private long elapsedTime; 


    public void run() 
    { 
     while(true) 
     { 
     currentTime = System.currentTimeMillis(); 
     elapsedTime = (currentTime - previousTime); // elapsed time in seconds 


     updateGame(elapsedTime/1000f); 

      try { 
       Thread.currentThread().sleep(1); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

     previousTime = currentTime; 
     } 
    } 
} 

Trong ví dụ này tôi chỉ ngủ cho 1ms (và từ sự hiểu biết của tôi với cách millisecond tính chính xác và chức năng ngủ các công trình này có lẽ giống như 5-10ms. Nếu tôi ngủ cho bất kỳ hơn này nó bắt đầu có ảnh hưởng đến tính chính xác của phát hiện va chạm của tôi và mô hình vật lý.

có một thực tế xấu để có vòng eo hẹp hoặc vòng với 1ms ngủ trong đó? có cái gì khác tôi nên làm gì để thay thế?

+1

Bạn nên sử dụng 'Thread.sleep (...)' thay vì 'Thread.currentThread() ngủ. (. ..) 'bởi vì nó là một phương pháp tĩnh; mã của bạn có thể cám dỗ bạn làm 'someOtherThread.sleep (...)' mà không ngủ 'someOtherThread'. – newacct

Trả lời

9

tôi đọc một bài thực sự tuyệt vời về hiệu quả và hiệu quả thực hiện các tính toán vật lý vòng lặp: Fix Your Timestep!

Khi một trò chơi đang chạy mà thường là ứng dụng chính mà người dùng quan tâm đến vòng lặp về rất chặt chẽ mà không phải là lớn của một thỏa thuận . Những gì bạn thực sự nên làm mặc dù lịch trình cập nhật của bạn. Bạn nên biết thời gian - tốc độ khung hình của bạn là bao lâu - khung của bạn phải thực thi. Bạn nên đo thời gian mà khung hình của bạn đã chụp và chỉ ngủ trong khoảng thời gian mà khung của bạn đã trừ đi thời gian khung đã biết. Bằng cách đó, hệ thống của bạn sẽ khóa thành tốc độ khung hình và không thay đổi theo lượng thời gian mà khung của bạn cần để hiển thị.

Một điều nữa là tôi không tin Chủ đề đó.giấc ngủ có độ phân giải rất tốt, hơn 5 mili giây, bạn có thể muốn tìm một bộ đếm thời gian chính xác hơn cho Java.

+0

Tôi có hai luồng, chuỗi updateGame của tôi và chuỗi hiển thị của tôi. Chuỗi hiển thị của tôi bị khóa với maxFrameRate khi bạn nói dựa trên thời gian đã trôi qua của nó. – mmcdole

+0

@joshperry, đọc bài viết ngay bây giờ – mmcdole

+0

Big upvote cho 'sửa chữa timestep của bạn'. Trở lại thời đại đen tối, chúng tôi sử dụng các kỹ thuật tương tự để biện minh cho văn bản! –

2

nó chỉ "xấu" nếu nó có tác động bất lợi đến cái gì đó khác trong hệ thống của bạn. Thay vì ngủ trong 1ms, bạn có thể chặn điều kiện wa rrants cập nhật, với tối thiểu là 1ms. Bằng cách đó bạn sẽ luôn ngủ ít nhất 1ms và lâu hơn nếu không có gì để làm.

2

Như Adam đã chỉ ra trong câu trả lời của mình, có thể có một tác động bất lợi đến hiệu suất của hệ thống.

Tôi cũng đã thử tạo trò chơi theo cách tương tự (có tính toán kết xuất và chuyển động trên các chuỗi riêng biệt) và tôi thấy rằng không có Thread.sleep sẽ khiến ứng dụng Java chiếm một phần rất quan trọng của CPU thời gian.

Một điều cần lưu ý là bản thân bộ hẹn giờ hệ thống. Như bạn đã đề cập, mặc dù phương pháp Thread.sleep mất khoảng mili giây để ngủ, nhưng độ chính xác đó phụ thuộc (như được ghi chú trong thông số API) trên bộ hẹn giờ do hệ điều hành cung cấp. Trong trường hợp hệ điều hành dựa trên Windows NT, số timer resolution is 10 milliseconds. (Xem thêm: System.currentTimeMillis vs System.nanoTime)

Có, đúng là có Thread.sleep có khả năng làm giảm hiệu suất của ứng dụng, nhưng không có điều đó có thể làm cho ứng dụng sử dụng hệ thống tăng vọt. Tôi có thể quyết định xem liệu ứng dụng có chiếm một phần đáng kể trong việc sử dụng hệ thống hay hoạt động tốt và chia sẻ thời gian CPU với các ứng dụng khác đang chạy trên hệ thống hay không.

0

Đối với trò chơi, có thể là không. Chỉ cần đảm bảo trò chơi của bạn tạm dừng khi công tắc chuyển đổi.

0

Bạn thực sự muốn sử dụng Thread.yield() trong trường hợp này. Có thể một luồng sẽ chạy liên tục và không cho phép bất kỳ chuỗi thời gian nào khác thực thi. Việc đặt một cuộc gọi năng suất vào cuối mỗi lần lặp lại sẽ cho phép trình lập lịch biểu gợi ý rằng đã đến lúc cho phép các luồng khác chạy.

1

Cũng xem xét người dùng máy tính xách tay, chạy vòng lặp liên tục sẽ giữ CPU chạy mạnh, và điều này sẽ nhai qua pin của họ (nhiều trò chơi flash có tội này). Một cái gì đó để xem xét khi quyết định có nên throttle vòng của bạn hay không.

1

Câu trả lời của joshperry là khá nhiều những gì bạn muốn, nhưng cũng có một vài cách về nó. Nếu bạn đang sử dụng nhiều chủ đề, bạn cũng phải đối phó với khóa vv Tùy thuộc vào kiến ​​trúc trò chơi của bạn mà có thể/có thể không phải là một việc lớn. Ví dụ, bạn có làm rất nhiều khóa, có rất nhiều thông điệp đi qua giữa các chủ đề vv Nếu bạn là một trò chơi truyền thống, bạn thường có một vòng lặp chính - tôi có một hàng đợi các đối tượng CMD (runnable nếu bạn thích, nhưng có thể cũng có nhiều bus sự kiện như trong tự nhiên) được thực hiện liên tục cho đến khi hàng đợi trống. Chủ đề sau đó đợi cho đến khi nó được báo hiệu rằng một cmd mới nằm trong hàng đợi. Đối với hầu hết các trò chơi, điều này thường là đủ. Vì vậy, câu hỏi sau đó sẽ trở thành như thế nào/khi nào cmds được thêm vào. Tôi sử dụng một bộ đếm thời gian/lịch trình (cũng lưu ý các ý kiến ​​về độ phân giải thời gian java) để thêm một cmd vào vòng lặp chính với tốc độ khung hình yêu cầu. Điều này có lợi thế là cũng được loại để máy tính xách tay vv Khi khởi động bạn cũng có thể chuẩn hệ thống để xem nó chạy nhanh như thế nào, và sau đó thiết lập một tỷ lệ khung hình thích hợp (ví dụ: bắt đầu với một cơ sở được hỗ trợ, sau đó làm việc để tối đa). Đo điểm chuẩn hoặc sử dụng gợi ý hiệu suất được chỉ định của người dùng (nghĩa là số lượng chi tiết dựng hình) có thể được sử dụng bởi từng loại cmd (ví dụ: cmd/sự kiện hiển thị xem xét cài đặt hiệu suất để biết chi tiết, v.v.). (lưu ý - cmds dont 'phải chạy được, chúng có thể giống như một bus sự kiện với các trình lắng nghe được gọi trên luồng chính). Ngoài ra nếu một công việc muốn sử dụng bộ xử lý đa luồng/lõi cho cmd (nếu mô hình kiểu sự kiện của nó - cá nhân tôi thích mô hình sự kiện - dễ dàng truy cập thông tin trạng thái được chia sẻ mà không cần người toàn cầu). sau đó có thể sinh ra nhiều tác vụ (giả sử sử dụng một nhóm luồng hiện có - vì vậy chi phí của các luồng mới không được nhấn từng cmd) và sau đó sử dụng một lớp kiểu rào chắn để đợi tất cả các nhiệm vụ hoàn thành. Phương pháp này thường làm cho khóa dễ dàng hơn, vì mỗi cmd (hoặc hệ thống) thường có các yêu cầu khóa khác nhau. Vì vậy, bạn có thể thực hiện chỉ là khóa cho hệ thống đó và không phải lo lắng về việc khóa giữa các hệ thống con - tức là. cho vật lý, bạn có thể khóa trên các bó của các đối tượng trong khu vực trò chơi, và mỗi chủ đề chia rẽ trong hồ bơi thread sau đó chỉ lo lắng về các đối tượng của nó tức là. thread1 xử lý đối tượng1 đến 20, đối tượng thread2 21-40 vv (đây chỉ là minh họa khái niệm về cách mỗi cmd có thể thực hiện một thuật toán khóa tùy chỉnh hoạt động tốt nhất cho những gì nó đang làm, mà không phải lo lắng về những hệ thống phụ khác đang làm gì với dữ liệu trạng thái được chia sẻ).

Điều quan trọng là để xem làm thế nào và tại sao bạn đang sử dụng chủ đề và khóa, vv

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