Hju*_*lle 11 c# haskell asynchronous
我刚刚阅读了使用await和async关键字在C#5.0中处理异步函数的新方法.从等待的C#参考考试:
private async Task SumPageSizesAsync()
{
// To use the HttpClient type in desktop apps, you must include a using directive and add a
// reference for the System.Net.Http namespace.
HttpClient client = new HttpClient();
// . . .
Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
byte[] urlContents = await getContentsTask;
// Equivalently, now that you see how it works, you can write the same thing in a single line.
//byte[] urlContents = await client.GetByteArrayAsync(url);
// . . .
}
Run Code Online (Sandbox Code Playgroud)
A Task<byte[]>表示将生成类型值的异步任务的Future byte[].await在a上使用关键字Task将基本上将函数的其余部分放在一个延续中,这将在任务完成时调用.任何await使用的函数都必须使用关键字async,Task<a>如果它返回类型则具有类型a.
所以线条
byte[] urlContents = await getContentsTask;
// Do something with urlContents
Run Code Online (Sandbox Code Playgroud)
会翻译成类似的东西
Task newTask = getContentsTask.registerContinuation(
byte[] urlContents => {
// Do something with urlContents
});
return newTask;
Run Code Online (Sandbox Code Playgroud)
这感觉很像Monad(变形金刚?).感觉它应该与CPS monad有一些关系,但也许不是.
这是我尝试编写相应的Haskell类型
-- The monad that async functions should run in
instance Monad Async
-- The same as the the C# keyword
await :: Async (Task a) -> Async a
-- Returns the current Task, should wrap what corresponds to
-- a async method in C#.
asyncFunction :: Async a -> Async (Task a)
-- Corresponds to the method Task.Run()
taskRun :: a -> Task a
Run Code Online (Sandbox Code Playgroud)
以及上述例子的粗略翻译
instance MonadIO Async -- Needed for this example
sumPageSizesAsync :: Async (Task ())
sumPageSizesAsync = asyncFunction $ do
client <- liftIO newHttpClient
-- client :: HttpClient
-- ...
getContentsTask <- getByteArrayAsync client url
-- getContentsTask :: Task [byte]
urlContents <- await getContentsTask
-- urlContents :: [byte]
-- ...
Run Code Online (Sandbox Code Playgroud)
这是Haskell中的相应类型吗?是否有任何Haskell库(或类似方式)实现处理异步函数/操作的方法?
另外:你能用CPS变压器构建它吗?
是的,该Control.Concurrent.Async模块确实解决了类似的问题(并且具有类似的界面),但是以完全不同的方式这样做.我猜这Control.Monad.Task将是一场更接近的比赛.我想要的是Futures的monadic界面,它在幕后使用Continuation Passing Style.
这是一个Task构建在async库之上的monad :
import Control.Concurrent.Async (async, wait)
newtype Task a = Task { fork :: IO (IO a) }
newTask :: IO a -> Task a
newTask io = Task $ do
w <- async io
return (wait w)
instance Monad Task where
return a = Task $ return (return a)
m >>= f = newTask $ do
aFut <- fork m
a <- aFut
bFut <- fork (f a)
bFut
Run Code Online (Sandbox Code Playgroud)
请注意,我没有检查monad法律,所以它可能不正确.
这是您定义在后台运行的原始任务的方法:
import Control.Concurrent (threadDelay)
test1 :: Task Int
test1 = newTask $ do
threadDelay 1000000 -- Wait 1 second
putStrLn "Hello,"
return 1
test2 :: Task Int
test2 = newTask $ do
threadDelay 1000000
putStrLn " world!"
return 2
Run Code Online (Sandbox Code Playgroud)
然后,您可以Task使用do符号来组合s ,这会创建一个准备运行的新延迟任务:
test3 :: Task Int
test3 = do
n1 <- test1
n2 <- test2
return (n1 + n2)
Run Code Online (Sandbox Code Playgroud)
运行fork test3将生成Task并返回一个您可以随时调用的未来,以请求结果,必要时阻止直到完成.
为了证明它有效,我将做两个简单的测试.首先,我将分叉test3而不要求它的未来,只是为了确保它正确生成复合线程:
main = do
fork test3
getLine -- wait without demanding the future
Run Code Online (Sandbox Code Playgroud)
这工作正常:
$ ./task
Hello,
world!
<Enter>
$
Run Code Online (Sandbox Code Playgroud)
现在我们可以测试当我们要求结果时会发生什么:
main = do
fut <- fork test3
n <- fut -- block until 'test3' is done
print n
Run Code Online (Sandbox Code Playgroud)
......也有效:
$ ./task
Hello,
world!
3
$
Run Code Online (Sandbox Code Playgroud)