Как остановить операцию «черный ящик»? - PullRequest
4 голосов
/ 11 февраля 2011

Я использую асинхронный делегат, который вызывает метод, который загружает XML-файл в XPathDocument.Если xml слишком большой, чтобы поместиться в памяти, он никогда не завершит загрузку.приведенный ниже код работает, если XML-файл успешно загружен в XPathDocument.Я смог использовать событие таймера, которое выполняет оператор asyncXpath.EndInvoke (result) и работает для завершения метода CreateDocument, но не останавливает загрузку XPathDocument.Я пришел к выводу, что единственное, что я могу сделать, - это выполнить инструкцию Application.End, чтобы убить приложение.Кто-нибудь знает, как остановить операцию черного ящика, такую ​​как загрузка XPathDocument.

delegate bool AsyncXpathQueryCaller(string xmlfile 

bool found = false; 
AsyncXpathQueryCaller asyncXpath = new 
AsyncXpathQueryCaller(CreateDocument); 
IAsyncResult result = asyncXpath.BeginInvoke(xmlfile, null, null); 
while (!result.IsCompleted) 
{ 
result.AsyncWaitHandle.WaitOne(100, false); 

} 
found = asyncXpath.EndInvoke(result);


private bool CreateDocument (string xmlfile)
{
XPathDocument doc = new XPathDocument(xmlfile);
}

Ответы [ 4 ]

1 голос
/ 11 февраля 2011

Как насчет использования FileInfo , прежде чем пытаться загрузить его и проверить размер?Если он слишком большой, просто пропустите его.

Примерно так:

FileInfo fi = new FileInfo(xmlfile);
if(fi.Length < /*some huge number*/)
{
  //load the file
}
0 голосов
/ 11 февраля 2011

По предложению Абэ Мисслера целесообразно проверить размер файла еще до того, как попытаться загрузить его в XPathDocument.

Как можно решить, каким должен быть предел ?

Точного правила нет, но я слышал, что люди говорят, что вы должны умножить размер файла на 5, и тогда результат будет близок к объему памяти, который потребуется XmlDocument для загрузки / анализа текста.

0 голосов
/ 11 февраля 2011

РЕДАКТИРОВАТЬ : Я только что понял, что KeithS приблизился к хорошему ответу.Основная идея заключается в том, что вы вызываете конструктор XPathDocument , который принимает Stream, который упаковывает FileStream.Объект, который вы передаете ему, должен реализовывать функцию Read(byte[], int, int) для вызова функции FileStream обернутой Read или выбросить исключение, если время операции истекло.Вот пример кода:

class XmlStream : FileStream
{
    DateTime deadline;

    public XmlStream(string filename, TimeSpan timeout)
           : base(filename, FileMode.Open)
    {
        deadline = DateTime.UtcNow + timeout;
    }

    public override int Read(byte[] array, int offset, int count)
    {
        if (DateTime.UtcNow > deadline)
            throw new TimeoutException();
        return base.Read(array, offset, count);
    }
}

Вот код, который читает document, но время ожидания истекает через 1 секунду:

    bool found = true;
    using(var stream = new XmlStream(document, TimeSpan.FromSeconds(1)))
    try
    {
        xpath = new XPathDocument(stream);
    }
    catch (TimeoutException)
    {
        found = false;
    }

Если вы создаете отдельный поток вместо выполненияBeginInvoke, вы можете просто прервать поток, когда отметится таймер (или кто-то нажмет «Отмена»).Хотя прерывание потоков обычно нежелательно, поскольку оно может удерживать блокировку или иметь глобальные данные в несогласованном состоянии, в этом случае все должно быть в порядке, поскольку ваш поток не будет удерживать блокировку или получать доступ к глобальным данным.

Вот код для этого метода, который делает то же самое, что и в предыдущем примере:

    bool found = false;
    thread = new Thread(() =>
    {
        xpath = new XPathDocument(document);
        found = true;
    });
    thread.Start();
    thread.Join(TimeSpan.FromSeconds(1));
    thread.Abort();

Если вам неудобно прерывать потоки в вашем собственном домене приложения, вы можете создать документ в другом домене приложения и вызвать AppDomain.Unload на это, если это займет слишком много времени.Это потребует некоторой сортировки, но, вероятно, не будет слишком много накладных расходов.

Лучший способ убить процесс - это запустить его в отдельном процессе и использовать некоторый интерфейс удаленного взаимодействия для доступа к нему.,Возможно, это даже сложнее, чем другие опции, так как вам нужно беспокоиться о поиске исполняемого файла, передаче параметров, о том, что какой-то пользователь его завершает, и т. Д.

0 голосов
/ 11 февраля 2011

Вы можете объявить FileStream и передать его конструктору, но перед этим посмотрите на его свойство Length, а если оно слишком длинное, просто верните ошибку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...