2017-09-11 21 views
5

Tôi đã tạo một số hàm Azure rất đơn giản. Họ đọc và ghi dữ liệu từ Couchbase (đang chạy trong Azure trên máy ảo).Chức năng Azure: Singleton cho đối tượng đắt tiền

Tôi quan tâm đến (các) kết nối mà tôi thực hiện cho Couchbase trong một hàm Azure. Tôi tạo một đối tượng Cluster mỗi lần. Đây là một hoạt động tốn kém, và tôi thường chỉ làm điều đó một lần trong một ứng dụng web bình thường. Nhưng trong chức năng Azure, tôi là new nạp nó mỗi lần.

Có rất nhiều tốn kém để thực hiện các đối tượng như thế này ngoài Couchbase. Có cách nào để tạo ra một singleton, hoặc một số loại đối tượng được chia sẻ mà chức năng Azure có thể tái sử dụng giữa các cuộc gọi?

Trả lời

3

Bạn có thể sử dụng singleton bình thường, tức là một tài sản tĩnh mà trả về ví dụ đơn lẻ. Như mọi khi, hãy cẩn thận với tính an toàn của luồng, ví dụ: sử dụng Lazy<T> như @Jesse đề xuất.

Bạn cũng có thể sử dụng hàm tạo tĩnh để thực hiện khởi tạo trước khi lệnh gọi đầu tiên đến Hàm của bạn được thực hiện. Hàm khởi tạo tĩnh là an toàn luồng theo định nghĩa.

Trong cả hai trường hợp, bạn sẽ có thể sử dụng lại những thứ đắt tiền giữa tất cả các cuộc gọi chạy trên cùng một cá thể (máy chủ).

+2

Sử dụng Lazy <> hoặc AsyncLazy <> cùng với các thuộc tính tĩnh giúp giảm thiểu bất kỳ vấn đề luồng tiềm ẩn nào –

4

Thuộc tính tĩnh cho các đối tượng kết nối đắt tiền của bạn sẽ hoạt động tốt, nhưng tôi khuyên bạn nên gói chúng trong Lazy<> để đảm bảo an toàn cho luồng.

Dựa trên các bài viết trên blog mẫu mà bạn liên kết với một ví dụ về làm cho tái sử dụng thùng trên tất cả các chức năng của bạn gọi một cách an toàn được bảo đảm chủ đề có thể trông như thế này:

public class FunctionClass 
{ 
    private static Lazy<IBucket> LazyBucket = new Lazy<IBucket>(() => 
    { 
     var uri = ConfigurationManager.AppSettings["couchbaseUri"]; 
     var cluster = new Cluster(new ClientConfiguration 
     { 
      Servers = new List<Uri> { new Uri(uri) } 
     }); 

     var bucketName = ConfigurationManager.AppSettings["couchbaseBucketName"]; 
     var bucketPassword = ConfigurationManager.AppSettings["couchbaseBucketPassword"]; 

     return cluster.OpenBucket(bucketName, bucketPassword); 
    }); 

    // Your actual function implementation 
    public static async Task Run() 
    { 
     // Here you are guaranteed to get back a shared connection object to your bucket that has been 
     // initalized only once in a thread safe way 
     var initalizedOnceBucket = LazyBucket.Value; 

     // do something with the bucket 
    } 
} 

Nếu việc xây dựng của bạn đối tượng đắt tiền mà nên được chia sẻ dựa trên một số cuộc gọi async (Tôi nghi ngờ Couchbase C# khách hàng có thể có phiên bản async của phương pháp của nó). Bạn có thể sử dụng AsyncLazy<> từ gói tuyệt vời Nito.AsyncEx Nuget được viết bởi Stephen Cleary. Thường xuyên Lazy<> được tích hợp vào .NET nên không yêu cầu bất kỳ phụ thuộc bên ngoài nào.

+0

Tôi ước tôi có thể cung cấp cho bạn cả dấu kiểm. Cảm ơn bạn vì câu trả lời! –

+1

Không vấn đề gì, Mikhail đã ở đây trước và câu trả lời của anh ấy là hoàn toàn chính xác. Chỉ muốn kêu gọi và thể hiện các mẫu mà tôi sử dụng trong các chức năng của riêng tôi –

5

Khi giao dịch với đơn trên Azure Chức năng, có một số cân nhắc. Một là trạng thái toàn cầu được chia sẻ giữa các lời gọi AF. Vì vậy, nếu một hàm được gọi một lần và sau đó một lần nữa sau đó (đủ nhanh để máy chủ lưu trữ không dỡ mã của bạn), thì việc khởi tạo chỉ xảy ra một lần. Một lưu ý khác là AF là hoàn toàn miễn phí để bắt đầu nhiều lệnh gọi AF đồng thời - vì vậy bất kỳ người dùng đơn lẻ nào cần phải là luồng an toàn (kể cả khởi tạo của chúng).

Điều này có nghĩa là bạn sẽ muốn sử dụng Lazy<T>/AsyncLazy<T>. Tuy nhiên, lưu ý rằng AF (với các loại này) sẽ giữ trạng thái đơn (sau khởi tạo) cho lần gọi tiếp theo của bạn ngay cả khi nó không thành công. Đây có thể là một vấn đề đặc biệt với điện toán đám mây bởi vì nếu có lỗi mạng (hoặc cấu hình) khi AF của bạn khởi động, bạn muốn khởi tạo lại để thử lại lệnh gọi AF tiếp theo.

Kết luận, bạn muốn sử dụng Lazy<T>/AsyncLazy<T> theo cách sao cho an toàn chủ đề không bảo toàn được lỗi.

Với Lazy<T>, điều này có nghĩa you have to use the LazyThreadSafetyMode.PublicationOnly flag vượt qua một chức năng để các nhà xây dựng (không chỉ ngầm sử dụng constructor mặc định cho T). Lưu ý rằng điều này có nghĩa là bạn cần đảm bảo rằng hàm khởi tạo của bạn chính là luồng an toàn vì nó có thể được thực thi bởi nhiều luồng cùng một lúc.

Với AsyncLazy<T>, you have to use the AsyncLazyFlags.RetryOnFailure flag. Vì AsyncLazy<T> về bản chất là một Lazy<Task<T>>, tác vụ khởi tạo không đồng bộ được "chia sẻ" trong số tất cả người gọi đồng thời, và sau đó được thay thế bằng nguyên tử với phiên bản Lazy<Task<T>> mới nếu nó không thành công. Vì vậy, hàm khởi tạo không đồng bộ không cần phải là luồng an toàn.

Kể từ khi nhận được tất cả điều này đúng (đặc biệt đối với nhiều độc thân) được thay sao chép và pasteish, tôi trừu tượng này ra cho the AF project I'm working on:

Mất một lúc để đến thời điểm này, nhưng tôi rất hài lòng với cách nó được bật ra. Ý nghĩa của blog về điều này cũng vậy ...

+2

Stephen cảm ơn câu trả lời tuyệt vời. Làm thế nào về podcast của tôi đôi khi để nói về nó, và thúc đẩy công việc của bạn :) –

+0

@MatthewGroves: Tôi rất muốn, cảm ơn! Tôi gặp lỗi từ mẫu email trên trang web của bạn, nhưng vui lòng gửi email cho tôi - [địa chỉ của tôi ở trên trang web của tôi] (https://stephencleary.com/contact/). –

+0

Các URL trong câu trả lời của bạn hiện là 404 - bất kỳ cơ hội nào bạn có thể sửa chúng hoặc đăng mã trong câu trả lời của bạn? – Cocowalla

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