我假設你關心分配一個不必要的對象。我認爲這樣的擔憂是值得讚揚的。
您可能之後是一個位圖API,其中通過Stream<byte>
提供PNG圖像的字節,然後在套接字需要時生成位圖API。
System.Drawing
似乎並不支持這種行爲,可能WIC
做(.NET包裝存在通過優良的SharpDX
庫)。
但是,這意味着在傳輸期間保留潛在的昂貴對象(位圖,畫筆等)。字節數組可能是更有效的方法來存儲結果。
另一種避免不必要地分配對象的方法是緩存它們。由於System.Drawing
對象是可變的,並且不能安全地從多個線程使用,所以它有點問題。但是,您可以使用ThreadLocal
爲每個線程創建緩存。
在下面的示例代碼中,大多數對象都按照Thread
進行了緩存。每個調用draw
創建的唯一對象是返回的字節數組,但這可能是對PNG數據的有效存儲(可能調用System.Drawing
分配對象,但我們無法控制該對象)。由於我沒有找到一種方法來偵聽線程的「死亡」,所以當線程不再需要對象時,使用dispose
方法手動處理對象是很重要的。
希望這是有趣的
open System
open System.Drawing
open System.Drawing.Imaging
open System.IO
open System.Threading
module BitmapCreator =
module internal Details =
let dispose (d : IDisposable) =
if d <> null then
try
d.Dispose()
with
| e ->() // TODO: log
// state is ThreadLocal, it means the resources gets initialized once per thread
let state =
let initializer() =
// Allocate all objects needed for work
let font = new Font("Courier", 24.0F)
let red = new SolidBrush(Color.Red)
let white = new SolidBrush(Color.White)
let bitmap = new Bitmap(600,400)
let g = Graphics.FromImage bitmap
let ms = new MemoryStream 1024
// disposer should be called when Thread is terminating to reclaim
// resources as fast as possible
let disposer() =
dispose ms
dispose g
dispose bitmap
dispose white
dispose red
dispose font
font, red, white, bitmap, g, ms, disposer
new ThreadLocal<_>(initializer)
// Draws text on a bitmap and returns that as a byte array
let draw text =
// Grab the state for the current thread
let font, red, white, bitmap, g, ms, _ = Details.state.Value
g.FillRectangle(white, 0.0F, 0.0F, 600.0F, 400.0F)
g.DrawString(text, font, red, 10.0F, 40.0F)
g.Flush()
// Resets the memory stream
// The capacity is preserved meaning as long as the generated
// images is equal or smaller in size no realloc is needed
ms.Seek (0L, SeekOrigin.Begin) |> ignore
ms.SetLength 0L
bitmap.Save(ms, ImageFormat.Png)
// Here a new array is allocated per call
// Depending on how FillRectangle/DrawString works this is hopefully our
// only allocation
ms.ToArray()
// Disposes all BitmapCreator resources held by the current thread
let dispose() =
let _, _, _, _, _, _, disposer = Details.state.Value
disposer()
[<EntryPoint>]
let main argv =
// Saves some bitmaps to file, the name include the thread pid in order
// to not overwrite other threads' images
let save() =
let texts = [|"Hello"; "There"|]
let tid = Thread.CurrentThread.ManagedThreadId
for text in texts do
File.WriteAllBytes (sprintf "%s_%d.png" text tid, BitmapCreator.draw text)
// Runs a in other thread, disposes BitmapCreator resources when done
let runInOtherThread (a : unit -> unit) =
let a() =
try
a()
finally
BitmapCreator.dispose()
let thread = Thread a
thread.Start()
thread.Join()
Environment.CurrentDirectory <- AppDomain.CurrentDomain.BaseDirectory
try
save() // Here we allocate BitmapCreator resources
save() // Since the same thread is calling the resources will reused
runInOtherThread save // New thread, new resources
runInOtherThread save // New thread, new resources
finally
BitmapCreator.dispose()
0
嗨@henrik的'MemoryStream'我想avoid.Basically我的aproach工作。所做的是在將圖像'Save'保存到'MemoryStream'後,然後將其轉換爲數組,然後作爲響應發送。我的感覺是,它可以作爲迴應直接發送。 – Adrian
您可以手動Suave一個流,就像我上面顯示的那樣,或者您可以使用同級函數'transferStream'自己將字節寫入套接字。這取決於您的保存實施。 – Henrik
這不是我的'Save'實現,它是'System.Drawing.Image'類方法。 '.net' api。我不知道如何訪問它。 – Adrian