2012-02-08 40 views
5

Đôi khi tôi muốn chạy một số lượng tối đa các hành động IO song song cùng một lúc cho hoạt động mạng, v.v. Tôi đã bỏ qua một hàm chuỗi đồng thời nhỏ hoạt động tốt với https://gist.github.com/810920, nhưng điều này không thực sự là một hồ bơi. phải hoàn thành trước khi những người khác có thể bắt đầu.Làm cách nào để tạo một nhóm chủ đề?

Các loại những gì tôi đang tìm kiếm sẽ là một cái gì đó như:

runPool :: Int -> [IO a] -> IO [a] 

và sẽ có thể hoạt động trên danh sách hữu hạn và vô hạn.

Gói ống trông giống như nó có thể đạt được điều này khá tốt, nhưng tôi cảm thấy có thể là một giải pháp tương tự với gist mà tôi đã cung cấp chỉ bằng cách sử dụng mvars, v.v., từ nền tảng haskell.

Có ai gặp phải một giải pháp thành ngữ mà không có bất kỳ phụ thuộc nặng nào không?

Trả lời

7

Bạn cần một hồ bơi thread, nếu bạn muốn một cái gì đó ngắn, bạn có thể lấy cảm hứng từ Control.ThreadPool (từ gói điều khiển động cơ mà còn cung cấp chức năng tổng quát hơn), ví dụ threadPoolIO chỉ là:

threadPoolIO :: Int -> (a -> IO b) -> IO (Chan a, Chan b) 
threadPoolIO nr mutator = do 
    input <- newChan 
    output <- newChan 
    forM_ [1..nr] $ 
     \_ -> forkIO (forever $ do 
      i <- readChan input 
      o <- mutator i 
      writeChan output o) 
    return (input, output) 

Nó sử dụng hai Chan để giao tiếp với bên ngoài nhưng đó thường là những gì bạn muốn, nó thực sự giúp viết mã mà không mess up.

Nếu bạn hoàn toàn muốn quấn nó lên trong một chức năng của loại của bạn, bạn có thể rút gọn các thông tin liên lạc quá:

runPool :: Int -> [IO a] -> IO [a] 
runPool n as = do 
    (input, output) <- threadPoolIO n (id) 
    forM_ as $ writeChan input 
    sequence (repeat (length as) $ readChan output) 

này sẽ không giữ trật tự của các hành động của bạn, đó là một vấn đề (rất dễ dàng chỉnh sửa bằng cách truyền chỉ mục của hành động hoặc chỉ sử dụng mảng thay vì lưu trữ các phản hồi)?

Lưu ý: chuỗi n sẽ vẫn tồn tại mãi mãi với phiên bản đơn giản này, thêm hành động "killAll" trả về threadPoolIO sẽ giải quyết vấn đề này một cách dễ dàng nếu bạn dự định tạo và thùng rác một số hồ bơi đó trong một ứng dụng chạy dài (nếu không, cho trọng lượng của các chủ đề trong Haskell, nó có lẽ không đáng làm phiền). Lưu ý rằng chức năng này chỉ hoạt động trên danh sách hữu hạn, vì IO thường nghiêm ngặt nên bạn không thể bắt đầu xử lý các phần tử của IO [a] trước khi toàn bộ danh sách được tạo ra, nếu bạn thực sự muốn bạn sẽ sử dụng IO lười biếng với unsafeInterleaveIO (có thể không phải là ý tưởng tốt nhất) hoặc hoàn toàn thay đổi mô hình của bạn và sử dụng một cái gì đó như ống dẫn để dòng kết quả của bạn.

+1

Nếu bạn không quá quen thuộc với loại RunPool của bạn, threadPoolIO chính xác hơn một chút: bạn có thể dễ dàng sử dụng lại nó ở một vài nơi trong chương trình của bạn sau khi tạo, bạn có thể kiểm soát tách danh sách vô hạn và nạp nó và đọc phản ứng bởi khối và như vậy ... – Jedai

+0

'threadPoolIO' có vẻ ổn. Tôi sẽ có một cái nhìn qua mã để xem cách này được thực hiện như tôi khá quan tâm đến cách tốt nhất để tạo ra một thread-pool cũng như biết phiên bản Hackage được ưa chuộng bởi cộng đồng. –

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