博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#截取屏幕源码 可直接截屏、截取当前窗口 实例下载
阅读量:798 次
发布时间:2019-03-25

本文共 4821 字,大约阅读时间需要 16 分钟。

【实例简介】

C#截取屏幕源码 可直接截屏、截取当前窗口 实例下载

【实例截图】

在这里插入图片描述

【核心代码】

private CopyScreen s;

public Form1()
{
InitializeComponent();
//try
//{
// s = new CopyScreen();
// s.GetScreenImage = new CopyScreen.GetImage(s_GetScreenImage);
//}
//catch (Exception ex) { MessageBox.Show(ex.Message); }
}

void s_GetScreenImage(Image p_Image)

{
pictureBox1.Image = p_Image;
}
private void button3_Click(object sender, EventArgs e)
{
//s.GerScreenFormRectangle();
MessageBox.Show(“未实现”);
}
private void button1_Click(object sender, EventArgs e)
{
Bitmap myImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics g = Graphics.FromImage(myImage);
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height));
IntPtr dc1 = g.GetHdc();
g.ReleaseHdc(dc1);
myImage.Save(@“c:\screen0.jpg”);
}

private void button2_Click(object sender, EventArgs e)

{
Bitmap myImage = new Bitmap(this.Width, this.Height);
Graphics g = Graphics.FromImage(myImage);
g.CopyFromScreen(new Point(this.Location.X, this.Location.Y), new Point(0, 0), new Size(this.Width, this.Height));
IntPtr dc1 = g.GetHdc();
g.ReleaseHdc(dc1);
myImage.Save(@“c:\screen1.jpg”);
}

以下内容无关:

-------------------------------------------分割线---------------------------------------------

go-cache 过期清理方案

func (c *cache) DeleteExpired() {

log.Printf(“start check at:%v”, time.Now())
var evictedItems []keyAndValue
now := time.Now().UnixNano()
c.mu.Lock()
for k, v := range c.items {
// “Inlining” of expired
if v.Expiration > 0 && now > v.Expiration {
ov, evicted := c.delete(k)
if evicted {
evictedItems = append(evictedItems, keyAndValue{k, ov})
}
}
}
c.mu.Unlock()
for _, v := range evictedItems {
c.onEvicted(v.key, v.value)
}
}

func (j *janitor) Run(c *cache) {

ticker := time.NewTicker(j.Interval)
for {
select {
case <-ticker.C:
c.DeleteExpired()
case <-j.stop:
ticker.Stop()
return
}
}
}

func runJanitor(c *cache, ci time.Duration) {

j := &janitor{
Interval: ci,
stop: make(chan bool),
}
c.janitor = j
go j.Run©
}

func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]Item) *Cache {

c := newCache(de, m)
// This trick ensures that the janitor goroutine (which–granted it
// was enabled–is running DeleteExpired on c forever) does not keep
// the returned C object from being garbage collected. When it is
// garbage collected, the finalizer stops the janitor goroutine, after
// which c can be collected.
C := &Cache{c}
if ci > 0 {
runJanitor(c, ci)
runtime.SetFinalizer(C, stopJanitor)
}
return C
}
可以看到 go-cache 每过一段时间(j.Interval, 这个值也是通过 go-cache.New 设置), 就会启动清理工作.

清理时原理:

RWMutex.Lock()

遍历整个map, 检查 map 中的 value 是否过期
RWMutex.Unlock()
同时, 还利用了 runtime.SetFinalizer 在 go-cache 生命周期结束时, 主动完成对过期清理协程的终止

源码分析总结

遍览整个 go-cache 源码, 会发现 go-cache 完全靠着 RWMutex 保证数据的正确性.

考虑下面的问题:

当 go-cache.New() 时设置的定时清理的时间过长, 同时 Set 的 key 的过期时间比较长, 这样会不会导致 go-cache.map 中的元素过多?

会不会当清理启动时, 锁定了 go-cache.map (注意这个时候是写锁), 由于 go-cache.map 中元素过多, 导致 map 一直被锁定, 那么这个时候所有的 Set 函数是不是就会产生 Lock 竞争?
使用 go-cache 的时候, 当某个接口的 QPS 很高, 程序里由于使用问题, 将某些不该往 go-cache 存的 value 也存了进去, 那么会不会导致 Set 之间的 Lock 竞争呢?
场景还原
利用下面的程序可以轻松还原上面的问题场景. 上面提出的问题, 都会造成 go-cache lock 竞争. 这里利用 pprof 查看程序的指标

var goroutineNums = flag.Int(“gn”, 2, “goroutine nums”)

func main() {
flag.Parse()
go func() {
log.Println(http.ListenAndServe(“localhost:6060”, nil))
}()

rand.Seed(time.Now().Unix())lc := cache.New(time.Minute*5, time.Minute*2)log.Printf("start at:%v", time.Now())aaaKey := "aaa:%d:buy:cnt"log.Println("set run over")for i := 0; i < *goroutineNums; i++ {	go func(idx int) {		for {			key := fmt.Sprintf(aaaKey, rand.Int())			newKey := fmt.Sprintf("%s:%d", key, rand.Int())			v := rand.Int()			lc.Set(newKey, v, time.Millisecond)		}	}(i)}// 查看 go-cache 中 key 的数量go func() {	ticker := time.NewTicker(time.Second)	for {		select {		case <-ticker.C:			log.Printf("lc size:%d", lc.ItemCount())		}	}}()select {}

}

模拟接口高QPS
./go-cache-test -gn 2000
2020/03/12 00:32:33 start at:2020-03-12 00:32:33.949073 +0800 CST m=+0.001343027
2020/03/12 00:32:34 lc size:538398
2020/03/12 00:32:35 lc size:1149109
high-qps

瞬间就会出现锁竞争

模拟 go-cache 启动清理时的情形

./go-cache-test -gn 2
2020/03/12 00:37:33 start at:2020-03-12 00:37:33.171238 +0800 CST m=+0.001457393
2020/03/12 00:40:35 lc size:54750220
2020/03/12 00:40:35 start clear at:2020-03-12 00:40:35.103586 +0800 CST m=+120.005547323
2020/03/12 00:41:51 lc size:33
2020/03/12 00:41:51 lc size:50
clear

会看到当清理 map 的时候, 如果 map 中的数据过多就会造成 Lock 竞争, 造成其他数据无法写入 map

总结

我使用的问题
背景: 某接口 QPS 有点高

当时考虑到用户购买状态(这个状态可能随时变化)如果能够在本地缓存中缓存 10s, 那么用户再次点进来的时候能从本地取了, 就造成大量的数据都写入了 map 中

由于接口 QPS 比较高, 设置用户购买状态时就可能造成竞争, 造成接口响应超时
go-cache 使用注意点
尽量存放那些相对不怎么变化的数据, 适用于所有的 local cache(包括 map, sync.map)
go-cache 的过期检查时间要设置相对较小, 也不能过小
那些高 QPS 的接口尽量不要去直接 Set 数据, 如果必须 Set 可以采用异步操作
监控 go-cache 里面 key 的数量, 如果过多时, 需要及时调整参数

转载地址:http://tetyk.baihongyu.com/

你可能感兴趣的文章