我有一个F#应用程序,它通过命名管道与java应用程序通信。其中F#充当服务器,java充当客户端。该应用程序大部分工作,除了F#符号“System.IO.IOException:所有管道实例都忙”错误偶尔。下面是F#和Java的异常和代码片段的完整堆栈跟踪。在解决此问题时,我们非常感谢您提供帮助
谢谢, Sudaly
完整堆栈跟踪:
Unhandled Exception: System.IO.IOException: All pipe instances are busy.
at Microsoft.FSharp.Control.CancellationTokenOps.Start@1143-1.Invoke(Exception e)
at <StartupCode$FSharp-Core>.$Control.loop@413-38(Trampoline this, FSharpFunc`2 action)
at Microsoft.FSharp.Control.Trampoline.ExecuteAction(FSharpFunc`2 firstAction)
at Microsoft.FSharp.Control.TrampolineHolder.Protect(FSharpFunc`2 firstAction)
at <StartupCode$FSharp-Core>.$Control.-ctor@473-1.Invoke(Object state)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
F#代码:
[<DataContract>]
type Quote = {
[<field: DataMember(Name="securityIdentifier") >]
RicCode:string
[<field: DataMember(Name="madeOn") >]
MadeOn:DateTime
[<field: DataMember(Name="closePrice") >]
Price:int
}
let globalPriceCache = new Dictionary<string, Quote>()
let ParseQuoteString (quoteString:string) =
let data = Encoding.Unicode.GetBytes(quoteString)
let stream = new MemoryStream()
stream.Write(data, 0, data.Length);
stream.Position <- 0L
let ser = Json.DataContractJsonSerializer(typeof<Quote array>)
let results:Quote array = ser.ReadObject(stream) :?> Quote array
results
let RefreshCache quoteList =
globalPriceCache.Clear()
quoteList
|> Array.iter(fun result->globalPriceCache.Add(result.RicCode, result))
let EstablishConnection() =
let pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut, 4)
pipeServer.WaitForConnection()
try
Some(new StreamReader(pipeServer))
with e ->
None
let rec MarketPriceCache() =
match EstablishConnection() with
|Some(sr) ->
// Read request from the stream.
let m_cache =
sr.ReadLine()
|> ParseQuoteString
|> RefreshCache
MarketPriceCache()
| _ -> ()
[<EntryPoint>]
let main args=
try
async {
MarketPriceCache()
} |> Async.Start
while true do
if globalPriceCache.Count > 0 then
//Business logic
System.Threading.Thread.Sleep(1000 * 50)
else
ignore(logInfo(sprintf "%s" "Price Cache is empty"))
System.Threading.Thread.Sleep(1000 * 65)
with e ->
ignore(logError e.Message)
ignore(logError e.StackTrace)
0
Java代码:
public void WatchForPrice()
{
while (true)
{
try
{
Map<String, SecurityQuoteCacheEntry> priceMap = getPriceCache().getCacheMap();
List<LocalSecurityQuote> localSecurityQuotes = new ArrayList<LocalSecurityQuote>();
if(priceMap != null)
{
Set<String> keySet = priceMap.keySet();
System.out.println("Key Size: " + keySet.size());
for(String key : keySet)
{
SecurityQuote quote = priceMap.get(key).getQuote();
if(quote != null)
{
LocalSecurityQuote localSecurityQuote = new LocalSecurityQuote();
localSecurityQuote.setClosePrice(quote.getClosePrice());
localSecurityQuote.setMadeOn(quote.getMadeOn());
localSecurityQuote.setSecurityIdentifier(key);
localSecurityQuotes.add(localSecurityQuote);
}
}
JSONSerializer serializer = new JSONSerializer();
String jsonString = serializer.serialize(localSecurityQuotes);
// Connect to the pipe
RandomAccessFile pipe = new RandomAccessFile("\\\\.\\pipe\\testpipe", "rw");
if (pipe != null )
{
// write to pipe
pipe.write(jsonString.getBytes());
pipe.close();
}
else
System.out.println("Pipe not found");
doPeriodicWait();
}
else
System.out.println("No Price data found");
}
catch (Exception e)
{
e.printStackTrace();
System.out.println(e.getMessage());
doPeriodicWait();
}
}
}
答案 0 :(得分:4)
这是一种预感,但问题可能是您没有关闭管道流阅读器?
let rec MarketPriceCache() =
match EstablishConnection() with
|Some(sr) ->
// Read request from the stream.
try
sr.ReadLine()
|> ParseQuoteString
|> RefreshCache
finally
sr.Close()
MarketPriceCache()
| _ -> ()
(不需要m_cache变量 - 你没有在任何地方使用它)
答案 1 :(得分:3)
每次创建NamedPipeServerStream
时都必须处置它。在代码中执行此操作的最简单方法是通过在StreamReader
周围添加MarketPriceCache
语句来处置use
内的let rec MarketPriceCache() =
match EstablishConnection() with
| Some(sr) ->
// Read request from the stream.
use reader = sr in
(
let m_cache =
reader.ReadLine()
|> ParseQuoteString
|> RefreshCache
)
MarketPriceCache()
| _ -> ()
:
using ... in
使用MarketPriceCache
的语法可以防止在递归调用{{1}}后读者的范围结束。