Когда вы выполняете метод async
, он начинает работать синхронно до тех пор, пока он не достигнет оператора await
, а остальная часть кода будет выполняться асинхронно, а выполнение вернется к вызывающему.
В вашем код callCount()
запускается синхронно с await task
, затем возвращается к Main()
методу, и поскольку вы не дожидаетесь завершения метода, программа заканчивается без метода count()
.
Вы можете увидеть желаемое поведение, изменив тип возвращаемого значения на Task
и вызывая Wait()
в методе Main()
.
static void Main(string[] args)
{
callCount().Wait();
}
static void count()
{
for (int i = 0; i < 5; i++)
{
System.Threading.Thread.Sleep(2000);
Console.WriteLine("count loop: " + i);
}
}
static async Task callCount()
{
Task task = new Task(count);
task.Start();
for (int i = 0; i < 3; i++)
{
System.Threading.Thread.Sleep(1000);
Console.WriteLine("Writing from callCount loop: " + i);
}
Console.WriteLine("just before await");
await task;
Console.WriteLine("callCount completed");
}
EDIT: Так выполняется ваш код:
(для лучшего понимания изменения типа CallCount()
возвращаются к Task
)
Main()
. CallCount()
. Count()
. await task;
. Это когда роль асинхронного ожидания играет свою роль. await
не похож на Wait()
, он не блокирует текущий поток до тех пор, пока задача не завершится, но вернет управление исполнением в метод Main()
и все остальные инструкции в CallCount()
(в данном случае только Console.WriteLine("callCount completed");
) будет исполнена после завершения задачи. Main()
вызов CallCount()
возвращает Task
(с оставшимися инструкциями CallCount()
и исходной задачей), и выполнение продолжается . Main()
продолжит завершение работы программы и уничтожаемых задач. Wait()
(если CallCount()
недействительно, чтобы вы не ожидали выполнения задачи), вы позволяете завершить задачу, удерживая ее в Main()
для выполнения Count()
и печатаемой «callCount». Если вы хотите дождаться окончания задания счетчика в CallCount()
, не возвращаясь к методу Main()
, вызовите task.Wait();
, вся программа будет ждать Count()
, но это не то, что await
будет делать.
Эта ссылка подробно описывает шаблон асинхронного ожидания.
H opes, эта диаграмма рабочего процесса вашего кода помогает вам.
Существует отличное сообщение в блоге, в том числе код C # об использовании графической библиотеки ImageMagick через Interop в TopTen Software Blog . Этот пост посвящен конкретно запуску ASP.net на linux под моно; однако код C # должен быть полностью совместим с копированием и вставкой, единственное, что вам нужно изменить, это атрибуты Interop, если вы работаете под окнами, ссылающимися на двоичный файл окна (DLL).
ImageMagick® - это программный пакет для создания, редактирования, компоновки или преобразования растровых изображений. Он может читать и записывать изображения в различных форматах (более 100), включая DPX, EXR, GIF, JPEG, JPEG-2000, PDF, PhotoCD, PNG, Postscript, SVG и TIFF. Используйте ImageMagick для изменения размера, переворота, зеркалирования, поворота, искажения, сдвига и преобразования изображений, настройки цветов изображения, применения различных спецэффектов или рисования текста, линий, полигонов, эллипсов и кривых Безье.
blockquote>Кроме того, в Codeplex есть еще ImageMagick .Net проект разработки , который завершает все для вас. Но он не показывает активного развития с 2009 года, поэтому он может отставать от текущей версии библиотеки ImageMagick. Для небольшой тривиальной процедуры изменения размера я, вероятно, придерживаюсь взаимодействия. Вам просто нужно внимательно следить за своей реализацией для собственной утечки памяти или невыпущенных ресурсов (сама библиотека хорошо протестирована и проверена сообществом).
Библиотека бесплатна и с открытым исходным кодом. Лицензия Apache 2 совместима как с личными, так и с коммерческими целями. См. ImageMagick License Page .
Библиотека полностью перекрестная платформа и реализует множество мощных процедур обработки и преобразования изображений, которые не найдены в GDI + (или не реализованы в моно) и имеют хорошая репутация как альтернатива для обработки изображений ASP.net.
Обновление: похоже, что обновленная версия .NET-оболочки здесь: http://magick.codeplex.com/
Вы можете посмотреть http://gd-sharp.sourceforge.net/ , который является оберткой для библиотеки GD. Я не тестировал его, но он кажется многообещающим.
Да, используйте классы WPF System.Windows.Media
. Будучи полностью управляемыми, они не страдают от тех же проблем, что и материал GDI.
Вот выдержка из некоторого кода MVC, который я использую для визуализации градиентов, чтобы дать вам представление о том, как получить из WPF Visual
в PNG:
using System;
using System.IO;
using System.Web.Mvc;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace MyMvcWebApp.Controllers
{
public class ImageGenController : Controller
{
// GET: ~/ImageGen/Gradient?color1=red&color2=pink
[OutputCache(CacheProfile = "Image")]
public ActionResult Gradient(Color color1, Color color2, int width = 1, int height = 30, double angle = 90)
{
var visual = new DrawingVisual();
using (DrawingContext dc = visual.RenderOpen())
{
Brush brush = new LinearGradientBrush(color1, color2, angle);
dc.DrawRectangle(brush, null, new Rect(0, 0, width, height));
}
return new FileStreamResult(renderPng(visual, width, height), "image/png");
}
static Stream renderPng(Visual visual, int width, int height)
{
var rtb = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Default);
rtb.Render(visual);
var frame = BitmapFrame.Create(rtb);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(frame);
var stream = new MemoryStream();
encoder.Save(stream);
stream.Position = 0;
return stream;
}
}
}
У меня было хорошее поведение из библиотеки Каира (http://www.cairographics.org) в среде веб-сервера ASP.Net. Я действительно перешел в cairo из WPF из-за плохой модели использования памяти WPF для веб-материалов.
WPF фактически имеет тенденцию выводить ваш рабочий процесс из памяти. Ни один из объектов WPF не реализует IDisposable
, и многие из них ссылаются на неуправляемую память, которая освобождается только через финализатор. Тяжелое использование WPF (особенно если ваш сервер значительно облагается ЦП) в конечном итоге приведет к выходу из памяти, потому что ваша очередь финализатора становится насыщенной. Например, когда я занимался профилированием своего приложения, очередь финализации имела более 50 000 объектов, многие из которых содержали ссылки на неуправляемую память. Каир вел себя намного лучше для меня, и его использование памяти было гораздо более предсказуемым, чем WPF.
Если вы заинтересованы в использовании cairo, возьмите libs с сайта GTK +. У них есть x86, а также набор двоичных файлов x64.
Единственным недостатком является то, что cairo не может читать / писать JPG изначально; однако вы можете легко адаптировать материал WPF для чтения / записи JPG и выполнить повторную выборку / масштабирование / рисование / что-то еще, используя Cairo.
ImageSharp - это кросс-платформенная 2D-библиотека с открытым исходным кодом. Это написано на C # поверх нового .NET Standard, без зависимости от любого API, специфичного для ОС.
В настоящее время он находится в предварительном выпуске MyGet (вам нужно будет добавить источник пакета в параметры VS или файл NuGet.config), но мы уже используем его с некоторыми очень положительными результатами.
Здесь вы можете найти очень хорошую статью от Microsoft Employee: Изменение размера изображений с сервера с использованием WPF / WIC вместо GDI + , в котором предлагается использовать WPF вместо GDI +.
В любом случае, в конце он утверждает следующее:
Я связался с командой WPF, чтобы получить окончательное слово о том, является ли это поддерживается. К сожалению, это не так, и соответственно обновляется документация. Я извиняюсь за любую путаницу, которая может быть вызвана. Мы смотрим на способы сделать эту историю более приемлемой в будущем.
blockquote>Таким образом, WPF также не поддерживается в веб-приложениях, и я считаю, что: -S
Большинство проблем, которые я прочитал, относятся к ресурсам, которые не располагаются должным образом.
Я использовал варианты этого кода снова и снова без проблем с веб-приложениями:
public void GenerateThumbNail(HttpPostedFile fil, string sPhysicalPath,
string sOrgFileName,string sThumbNailFileName,
System.Drawing.Imaging.ImageFormat oFormat, int rez)
{
try
{
System.Drawing.Image oImg = System.Drawing.Image.FromStream(fil.InputStream);
decimal pixtosubstract = 0;
decimal percentage;
//default
Size ThumbNailSizeToUse = new Size();
if (ThumbNailSize.Width < oImg.Size.Width || ThumbNailSize.Height < oImg.Size.Height)
{
if (oImg.Size.Width > oImg.Size.Height)
{
percentage = (((decimal)oImg.Size.Width - (decimal)ThumbNailSize.Width) / (decimal)oImg.Size.Width);
pixtosubstract = percentage * oImg.Size.Height;
ThumbNailSizeToUse.Width = ThumbNailSize.Width;
ThumbNailSizeToUse.Height = oImg.Size.Height - (int)pixtosubstract;
}
else
{
percentage = (((decimal)oImg.Size.Height - (decimal)ThumbNailSize.Height) / (decimal)oImg.Size.Height);
pixtosubstract = percentage * (decimal)oImg.Size.Width;
ThumbNailSizeToUse.Height = ThumbNailSize.Height;
ThumbNailSizeToUse.Width = oImg.Size.Width - (int)pixtosubstract;
}
}
else
{
ThumbNailSizeToUse.Width = oImg.Size.Width;
ThumbNailSizeToUse.Height = oImg.Size.Height;
}
Bitmap bmp = new Bitmap(ThumbNailSizeToUse.Width, ThumbNailSizeToUse.Height);
bmp.SetResolution(rez, rez);
System.Drawing.Image oThumbNail = bmp;
bmp = null;
Graphics oGraphic = Graphics.FromImage(oThumbNail);
oGraphic.CompositingQuality = CompositingQuality.HighQuality;
oGraphic.SmoothingMode = SmoothingMode.HighQuality;
oGraphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
Rectangle oRectangle = new Rectangle(0, 0, ThumbNailSizeToUse.Width, ThumbNailSizeToUse.Height);
oGraphic.DrawImage(oImg, oRectangle);
oThumbNail.Save(sPhysicalPath + sThumbNailFileName, oFormat);
oImg.Dispose();
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
}