2013-03-22 11 views
19

Tôi biết bạn có thể xác định các hàm được gọi là init trong bất kỳ gói nào và chức năng này sẽ được thực hiện trước main. Tôi sử dụng tính năng này để mở tệp nhật ký và kết nối DB của mình.Khi truy cập, có cách nào để thực thi mã khi chấm dứt chương trình không?

Có cách nào để xác định mã sẽ được thực hiện khi chương trình kết thúc, vì nó đến cuối chức năng main hoặc do nó bị gián đoạn? Cách duy nhất tôi có thể nghĩ đến là bằng cách gọi một cách thủ công một hàm deqered terminate trên mỗi gói được sử dụng bởi chính, nhưng đó là khá tiết và dễ bị lỗi.

+1

là [câu hỏi này liên quan] (http://stackoverflow.com/questions/8403862/do-actions-on-end-of-execution) hữu ích? Đó là cách tôi thực hiện các hành động khi kết thúc thực thi. –

Trả lời

27

Chức năng C atexit được các nhà phát triển Go xem xét và ý tưởng chấp nhận nó đã bị từ chối.

Từ một trong những liên quan thread tại golang-hạt:

Russ Cox:

Atexit có thể có ý nghĩa trong single-ren, ngắn ngủi chương trình, nhưng tôi nghi ngờ rằng nó có một đặt trong máy chủ đa luồng dài chạy dài. Tôi đã nhìn thấy nhiều chương trình C++ treo trên lối ra vì chúng đang chạy các trình phá hủy toàn cầu mà không thực sự cần phải chạy và các trình phá hủy đó đang dọn dẹp và giải phóng bộ nhớ sẽ được hệ điều hành thu hồi , nếu chỉ có chương trình mới có thể nhận được cuộc gọi hệ thống thoát. So với tất cả nỗi đau đó, cần gọi Flush khi bạn đang một bộ đệm có vẻ hoàn toàn hợp lý và là cần thiết để thực hiện chính xác các chương trình dài hạn .

Thậm chí bỏ qua vấn đề đó, atexit giới thiệu nhiều hơn đề kiểm soát, và bạn phải trả lời những câu hỏi như làm tất cả các goroutines khác dừng lại trước khi xử lý atexit chạy? Nếu không, làm thế nào để họ tránh can nhiễu? Nếu vậy, điều gì sẽ xảy ra nếu một khóa mà trình xử lý cần? Và cứ tiếp tục.

Tôi hoàn toàn không muốn thêm Atexit.

Ian Lance Taylor:

duy nhất cơ chế hoàn toàn đáng tin cậy là một chương trình wrapper để gọi chương trình thực và làm việc dọn dẹp khi chương trình thực hoàn tất. Điều đó là đúng trong bất kỳ ngôn ngữ nào, không chỉ Go.

Trong ý kiến ​​hơi bị biến dạng của tôi, os.AtExit không phải là một ý tưởng tuyệt vời. Đó là một cơ sở không có cấu trúc khiến cho mọi thứ xảy ra tại thời điểm xuất cảnh chương trình theo thời gian không thể đoán trước. Nó dẫn đến các tình huống kỳ lạ như các chương trình mất nhiều thời gian để thoát, một hoạt động phải là rất nhanh. Nó cũng dẫn đến các chức năng kỳ lạ như hàm Cexex, nhiều hay ít có nghĩa là các hàm thoát-nhưng-không-chạy-atexit.

Điều đó nói rằng, tôi nghĩ rằng một chức năng thoát đặc biệt tương ứng với chức năng init là một ý tưởng thú vị. Nó sẽ có cấu trúc os.AtExit thiếu (cụ thể là, các hàm thoát được chạy theo thứ tự ngược lại khi các hàm init được chạy).

Nhưng chức năng thoát sẽ không giúp bạn nếu chương trình của bạn bị hạt nhân giết hoặc bị treo vì bạn gọi một số mã C bị phân đoạn vi phạm.

+2

Cảm ơn bạn, đó là một chủ đề rất thú vị. – Fabien

0

Nói chung, tôi đồng ý với câu trả lời của jnml. Tuy nhiên, nếu bạn vẫn muốn thực hiện, bạn có thể sử dụng defer trong chức năng main(), như sau: http://play.golang.org/p/aUdFXHtFOM.

+9

Trì hoãn các hàm từ 'main' chỉ hoạt động khi chương trình chấm dứt bằng cách kết thúc' main', không phải nếu nó thoát qua 'os.Exit', trái ngược với' atexit' ban đầu cũng hoạt động khi gọi 'exit'. – guelfey

+3

Nó cũng không hoạt động khi chương trình chấm dứt với một 'hoảng loạn' không được phục hồi. – peterSO

+4

@peterSO Tuy nhiên, bạn có thể khôi phục trong hàm bị trì hoãn, do đó, không có đối số thực sự nào chống lại 'trì hoãn' trong' main'. – nemo