c#在setter中进行线程化

时间:2015-11-04 10:22:29

标签: c# .net multithreading

在visual studio 2015社区中使用c#,尝试将将base64编码的字符串转换为图像的代码转换为线程化任务,以减少瓶颈。

这是有效的代码:

    private string _logoBase64;
    public string logoBase64
    {
        get { return _logoBase64; }
        set
        {
            _logoBase64 = value;
            setLogo();
        }
    }
    public ImageSource logo { get; set; }
            private void setLogo()
    {
        if ((this.logoBase64 != null) && (this.logoBase64.Length > 0))
        {
            string _logoBase64 = this.logoBase64
                .Replace("data:image/png;base64,", "")
                .Replace("data:image/gif;base64,", "")
                .Replace("data:image/jpeg;base64,", "");
            var image = new BitmapImage();
            try
            {
                image.BeginInit();
                image.StreamSource = new MemoryStream(Convert.FromBase64String(_logoBase64));
                image.EndInit();
                this.logo = image;
            }
            catch (Exception e)
            {
                Program.Errors.Add(e.Message + "\n" + e.StackTrace);
                if (Program.environment == "development")
                {
                    Console.WriteLine(e.Message);
                }
            }
        }
    }

使用this示例,我尝试将其转换为线程化任务:

    internal Task setLogoASync(string b64, CancellationToken cancellationToken)
    {
        return Task.Run(() =>
        {
            var image = new BitmapImage(); 
            if ((b64 != null) && (b64.Length > 0))
            {
                b64 = b64
                    .Replace("data:image/png;base64,", "")
                    .Replace("data:image/gif;base64,", "")
                    .Replace("data:image/jpeg;base64,", "");

                try
                {
                    image.BeginInit();
                    image.StreamSource = new MemoryStream(Convert.FromBase64String(b64));
                    image.EndInit();
                    this.logo = image;
                }
                catch (Exception e)
                {
                    Program.Errors.Add(e.Message + "\n" + e.StackTrace);
                    if (Program.environment == "development")
                    {
                        Console.WriteLine(e.Message);
                    }
                }
            }
            this.logo = image;
        }, cancellationToken);
    }

但问题是setter必须是异步的,但它不可能。有办法解决这个问题吗?

2 个答案:

答案 0 :(得分:2)

setter的一般建议是它们只应用于非常短的运行操作。

最好完全删除它,而只是提供一个公共方法。

原因在于,作为程序员,我不需要考虑调用setter的意外影响和副作用。

让setter创建一个线程在计算时间和使用的资源(例如CPU和内存)方面是一个意想不到的暗示。

答案 1 :(得分:2)

每次修改图像时,不要尝试计算Base64实现,而是在第一次实际请求时使用Lazy<T>来计算它。

private Lazy<ImageSource > _image;
public ImageSource logo
{
    get { return _image.Value; }
}

private string _logoBase64;
public string logoBase64
{
    get { return _logoBase64; }
    set
    {
        _logoBase64 = value;
        //Can't reset a Lazy, so we create a new one.
        _image=new Lazy<ImageSource>(()=>imageFromBase64()));
    }
}

//Initialize the Lazy in the constructor
public MyClass()
{
    _image=new Lazy<ImageSource>(()=>imageFromBase64())l
}

ImageSource imageFromBase64()
{
   var image = new BitmapImage(); 
   if ((b64 != null) && (b64.Length > 0))
   {
            b64 = b64
                .Replace("data:image/png;base64,", "")
                .Replace("data:image/gif;base64,", "")
                .Replace("data:image/jpeg;base64,", "");

            try
            {
                image.BeginInit();
                image.StreamSource = new MemoryStream(Convert.FromBase64String(b64));
                image.EndInit();
            }
            catch (Exception e)
            {
                Program.Errors.Add(e.Message + "\n" + e.StackTrace);
                if (Program.environment == "development")
                {
                    Console.WriteLine(e.Message);
                }
            }
    }
    return image;
}

为了避免第一个logo请求的延迟,您可以在一次性任务中启动延迟评估。 Lazy确保对其内容的并发访问,因此在有人请求徽标之前,任务是否完成无关紧要

public string logoBase64
{
    get { return _logoBase64; }
    set
    {
        _logoBase64 = value;
        //Can't reset a Lazy, so we create a new one.
        var newLazy=new Lazy<ImageSource>(()=>imageFromBase64()));
        //Start throwaway task before assigning to backing field,
        //to avoid race conditions
        Task.Run(()=>newLazy.Value);
        _image=newLazy;
    }
}