찾다
백엔드 개발C#.Net 튜토리얼.NET의 비동기 비동기, 스레드 멀티스레딩

.NET의 비동기 비동기, 스레드 멀티스레딩

1. Task Task

System.Threading.Tasks는 .NET4에서 도입됐는데, 기존 쓰레드에 대한 API가 너무 많아 제어가 불편하고, ThreadPool 제어 능력도 너무 약하다. 스레드 연속화, 차단, 취소, 타임아웃 등의 기능이 불편하므로 Task는 스레드 기능을 추상화하고 백그라운드에서 ThreadPool을 사용합니다

1 작업을 시작하려면

TaskFactory 클래스나 생성자를 사용할 수 있습니다. 및 위임할 Task 클래스의 Start() 메소드 Object 유형의 입력 매개변수를 제공할 수 있으므로 어떤 데이터도 태스크에 전달할 수 있습니다. 또한 일반적으로 사용되는 Task.Run

TaskFactory taskFactory = new TaskFactory();
taskFactory.StartNew(() => 
{
    Console.WriteLine($"tid={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
});
Task.Factory.StartNew(() =>
{
    Console.WriteLine($"tid={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
});
Task task = new Task(() =>
{
    Console.WriteLine($"tid={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
});
task.Start();

Task 클래스 인스턴스 메소드만 누락됩니다. 작업을 시작하려면 Start()가 필요합니다. 물론 작업을 시작하려면 RunSynchronously()를 사용할 수 있습니다. 작업을 동기적으로 실행하려면 메인 스레드를 기다려야 합니다. 즉, 작업을 실행하기 위해 메인 스레드를 사용합니다

Task task = new Task(() =>
{
    Thread.Sleep(10000);
    Console.WriteLine($"tid={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
});
task.RunSynchronously();

2. 연속 차단

스레드에서는 대기를 차단하기 위해 조인을 사용합니다. 여러 스레드를 제어하는 ​​것은 편리하지 않습니다. Task에서는 인스턴스 메서드 Wait를 사용하여 단일 작업을 차단하거나 정적 메서드 WaitAll 및 WaitAny를 사용하여 여러 작업을 차단합니다

var task = new Task(() =>
{
    Thread.Sleep(5*1000);
    Console.WriteLine($"tid={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
});
var task2 = new Task(() =>
{
    Thread.Sleep(10 * 1000);
    Console.WriteLine($"tid={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
});
task.Start();
task2.Start();
//task.Wait();//单任务等待
//Task.WaitAny(task, task2);//任何一个任务完成就继续
Task.WaitAll(task, task2);//任务都完成才继续

메인 스레드를 차단하지 않고 하나 또는 여러 작업이 완료된 후 다른 작업을 실행하려는 경우 , 작업 정적 메서드 WhenAll 및 WhenAny를 사용할 수 있으며 작업을 반환하지만 이 작업에서는 작업을 제어할 수 없습니다. WhenAll 및 WhenAny의 작업이 완료되면 자동으로 완료되고 작업의 ContinueWith를 호출합니다. 작업 완료 후 즉시 다른 작업을 시작하는 방법 작업

Task.WhenAll(task, task2).ContinueWith((t) =>
{
    Console.WriteLine($"tid={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
});
Task.Factory工厂中也存在类似ContinueWhenAll和ContinueWhenAny

3. 작업 계층

한 작업이 끝난 후 다른 작업을 실행할 수 있을 뿐만 아니라 시작되는 작업 내에서 작업을 시작할 수도 있습니다. 부모-자식 계층

var parentTask = new Task(()=> 
{
    Console.WriteLine($"parentId={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
    Thread.Sleep(5*1000);
    var childTask = new Task(() =>
    {
        Thread.Sleep(10 * 1000);
        Console.WriteLine($"childId={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}")
    });
    childTask.Start();
});
parentTask.Start();

하위 작업 전에 상위 작업이 종료되면 상위 작업의 상태는 WaitingForChildrenToComplete입니다. 하위 작업도 완료되면 상위 작업의 상태는 RanToCompletion이 됩니다. 물론 TaskCreationOptions 열거 매개변수를 지정하면 됩니다. 작업 생성 시 선택 동작

4. 열거 매개변수

작업 생성 시 TaskCreationOptions 열거 매개변수에 대한 간략한 소개입니다.

AttachedToParent: 작업 계층의 상위에 작업을 연결하도록 지정합니다. 이는 상위 작업이 완료될 때까지 기다려야 함을 의미합니다. 실행을 계속하기 전에 하위 작업을 삭제합니다. 효과는 WaitAll과 동일합니다. 위의 예에서 하위 작업을 생성할 때 TaskCreationOptions.AttachedToParent를 지정하면 상위 작업도 대기할 때 하위 작업이 끝날 때까지 기다립니다.

DenyChildAttach: 하위 작업이 상위 작업에 연결되는 것을 허용하지 않습니다.

LongRunning: 장기 실행 작업을 지정합니다. 이 작업이 시간이 오래 걸릴 것임을 미리 알고 있다면 이 옵션을 설정하는 것이 좋습니다. 이러한 방식으로 작업 스케줄러는 ThreadPool 스레드를 사용하는 대신 스레드 스레드를 생성합니다. ThreadPool 스레드를 반환하지 않고 오랫동안 점유하기 때문에 필요할 때 스레드 풀에서 새 스레드가 열릴 수 있어 일정 압박이 발생할 수 있습니다.

PreferFairness: 작업을 최대한 공정하게 배열합니다. 즉, 이전에 예약된 작업이 더 많아질 것입니다. 더 일찍 실행되고 나중에 실행되도록 예약된 작업은 나중에 실행될 가능성이 더 높습니다. 실제로 작업은 스레드 풀의 전역 대기열에 배치되며 작업자 스레드가 이를 위해 경쟁하게 됩니다. 기본값은 로컬 대기열에 있습니다.

또 다른 열거 매개변수는 ContinueWith 메소드의 TaskContinuationOptions 열거 매개변수입니다. 위와 동일한 기능을 가진 여러 열거값 외에도 작업 연속 취소를 제어하는 ​​등의 기능도 있습니다.

LazyCancellation: 연속 취소의 경우 이전 작업이 완료될 때까지 연속 완료를 방지합니다. 그것은 무엇을 의미합니까?

CancellationTokenSource source = new CancellationTokenSource();
source.Cancel();
var task1 = new Task(() => 
{
    Console.WriteLine($"task1 id={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
});
var task2 = task1.ContinueWith(t =>
{
    Console.WriteLine($"task2 id={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
},source.Token);
var task3 = task2.ContinueWith(t =>
{
    Console.WriteLine($"task3 id={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
});
task1.Start();

위 예시에서는 task1->task2->task3을 순차적으로 실행한 후 CancellationToken을 통해 task2의 실행을 취소하려고 했습니다. 결과는 어떻게 될까요? 결과적으로 task1과 task3이 병렬로 실행되고(task3도 실행되고 task1과 병렬로 실행되므로 원래 체인이 두 개의 체인이 됨)

LazyCancellation,
var task2 = task1.ContinueWith(t =>
{
    Console.WriteLine($"task2 id={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
},source.Token,TaskContinuationOptions.LazyCancellation,TaskScheduler.Current);

이런 식으로 이후에 task1의 실행이 완료되면 Task2는 source.Token만 판단합니다. 취소인 경우 task3의 다음 실행은 원래 순서를 보장합니다.

ExecuteSynchronously: 연속 작업이 실행되어야 함을 지정합니다. 예를 들어, 위의 예에서 이 매개변수가 연속 작업 task2에 지정되면 Task2는 task1을 실행하는 스레드를 사용하여 실행됩니다. 이렇게 하면 스레드 전환이 방지되고 공유 리소스에 대한 일부 액세스가 허용됩니다. 지정하지 않으면 랜덤이지만 task1의 스레드도 사용할 수 있습니다

NotOnRanToCompletion: 이전 작업이 완료되지 않은 경우 연속 작업을 실행해야 합니다.

OnlyOnRanToCompletion: 이전 작업이 완료되면 연속 작업을 실행해야 합니다. Completed

NotOnFaulted, OnlyOnCanceled, OnlyOnFaulted 등

5. 작업 취소

이전 기사에서 Thread를 사용할 때 작업 취소 여부를 표시하기 위해 isStop 변수를 사용했습니다. 문제를 일으킵니다. CancellationTokenSource 클래스는 작업 취소를 구체적으로 처리하기 위해 제안되었습니다. 일반적인 사용법은 아래 코드 주석을 참조하세요.

CancellationTokenSource source = new CancellationTokenSource();//构造函数中也可指定延迟取消
//注册一个取消时调用的委托
source.Token.Register(() =>
{
    Console.WriteLine("当前source已经取消,可以在这里做一些其他事情(比如资源清理)...");
});
var task1 = new Task(() => 
{
    while (!source.IsCancellationRequested)
    {
        Console.WriteLine($"task1 id={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
    }
},source.Token);
task1.Start();
//source.Cancel();//取消
source.CancelAfter(1000);//延时取消

6.

让子线程返回结果,可以将信息写入到线程安全的共享变量中去,或则使用可以返回结果的任务。使用Task的泛型版本Task,就可以定义返回结果的任务。Task是继承自Task的,Result获取结果时是要阻塞等待直到任务完成返回结果的,内部判断没有完成则wait。通过TaskStatus属性可获得此任务的状态是启动、运行、异常还是取消等

var task = new Task<string>(() =>
{
     return "hello ketty";
});
task.Start();
string result = task.Result;

7、异常

可以使用AggregateException来接受任务中的异常信息,这是一个聚合异常继承自Exception,可以遍历获取包含的所有异常,以及进行异常处理,决定是否继续往上抛异常等

var task = Task.Factory.StartNew(() =>
{
    var childTask1 = Task.Factory.StartNew(() =>
    {
        throw new Exception("childTask1异常...");
    },TaskCreationOptions.AttachedToParent);
    var childTask12= Task.Factory.StartNew(() =>
    {
        throw new Exception("childTask2异常...");
    }, TaskCreationOptions.AttachedToParent);
});
try
{
    try
    {
        task.Wait();
    }
    catch (AggregateException ex)
    {
        foreach (var item in ex.InnerExceptions)
        {
            Console.WriteLine($"message{item.InnerException.Message}");
        }
        ex.Handle(x =>
        {
            if (x.InnerException.Message == "childTask1异常...")
            {
                return true;//异常被处理,不继续往上抛了
            }
            return false;
        });
    }
}
catch (Exception ex)
{
    throw;
}

二、并行Parallel

1、Parallel.For()、Parallel.ForEach()

在.NET4中,另一个新增的抽象的线程时Parallel类。这个类定义了并行的for和foreach的静态方法。Parallel.For()和Parallel.ForEach()方法多次调用一个方法,而Parallel.Invoke()方法允许同时调用不同的方法。首先Parallel是会阻塞主线程的,它将让主线程也参与到任务中

Parallel.For()类似于for允许语句,并行迭代同一个方法,迭代顺序没有保证的

ParallelLoopResult result = Parallel.For(0, 10, i =>
{
    Console.WriteLine($"{i} task:{Task.CurrentId} thread:{Thread.CurrentThread.ManagedThreadId}");
});
Console.WriteLine(result.IsCompleted);

也可以提前中断Parallel.For()方法。For()方法的一个重载版本接受Action类型参数。一般不使用,像下面这样,本想大于5就停止,但实际也可能有大于5的任务已经在跑了。可以通过ParallelOptions传入允许最大线程数以及取消Token等

ParallelLoopResult result = Parallel.For(0, 10, new ParallelOptions() { MaxDegreeOfParallelism = 8 },(i,loop) =>
{
    Console.WriteLine($"{i} task:{Task.CurrentId} thread:{Thread.CurrentThread.ManagedThreadId}");
    if (i > 5)
    {
        loop.Break();
    }
});

2、Parallel.For

For还有一个高级泛型版本,相当于并行的聚合计算

ParallelLoopResult For<TLocal>(int fromInclusive, int toExclusive, Func<TLocal> localInit, Func<int, ParallelLoopState, TLocal, TLocal> body, Action<TLocal> localFinally);

像下面这样我们求0…100的和,第三个参数更定一个种子初始值,第四个参数迭代累计,最后聚合

int totalNum = 0;
Parallel.For<int>(0, 100, () => { return 0; }, (current, loop, total) =>
{
    total += current;
    return total;
}, (total) =>
{
    Interlocked.Add(ref totalNum, total);
});

上面For用来处理数组数据,ForEach()方法用来处理非数组的数据任务,比如字典数据继承自IEnumerable的集合等

3、Parallel.Invoke()

Parallel.Invoke()则可以并行调用不同的方法,参数传递一个Action的委托数组

Parallel.Invoke(() => { Console.WriteLine($"方法1 thread:{Thread.CurrentThread.ManagedThreadId}"); }
    , () => { Console.WriteLine($"方法2 thread:{Thread.CurrentThread.ManagedThreadId}"); }
    , () => { Console.WriteLine($"方法3 thread:{Thread.CurrentThread.ManagedThreadId}"); });

4、PLinq

Plinq,为了能够达到最大的灵活度,linq有了并行版本。使用也很简单,只需要将原始集合AsParallel就转换为支持并行化的查询。也可以AsOrdered来顺序执行,取消Token,强制并行等

var nums = Enumerable.Range(0, 100);
var query = from n in nums.AsParallel()
            select new
            {
                thread=$"tid={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}"
            };

三、异步等待AsyncAwait

异步编程模型,可能还需要大篇幅来学习,这里先介绍下基本用法,内在本质需要用ILSpy反编译来看,以后可能要分专题总结。文末先给几个参考资料,有兴趣自己阔以先琢磨琢磨鸭

1、简单使用

这是.NET4.5开始提供的一对语法糖,使得可以较简便的使用异步编程。async用在方法定义前面,await只能写在带有async标记的方法中,任何方法都可以增加async,一般成对出现,只有async没有意义,只有await会报错,请先看下面的示例

private static async void AsyncTest()
{
    //主线程执行
    Console.WriteLine($"before await ThreadId={Thread.CurrentThread.ManagedThreadId}");
    TaskFactory taskFactory = new TaskFactory();
    Task task = taskFactory.StartNew(() =>
    {
        Thread.Sleep(3000);
        Console.WriteLine($"task ThreadId={Thread.CurrentThread.ManagedThreadId}");
    });
    await task;//主线程到这里就返回了,执行主线程任务
    //子线程执行,其实是封装成委托,在task之后成为回调(编译器功能  状态机实现) 后面相当于task.ContinueWith()
    //这个回调的线程是不确定的:可能是主线程  可能是子线程  也可能是其他线程,在winform中是主线程
    Console.WriteLine($"after await ThreadId={Thread.CurrentThread.ManagedThreadId}");
}

一般使用async都会让方法返回一个Task的,像下面这样复杂一点的

private static async Task<string> AsyncTest2()
{
    Console.WriteLine($"before await ThreadId={Thread.CurrentThread.ManagedThreadId}");
    TaskFactory taskFactory = new TaskFactory();
    string x = await taskFactory.StartNew(() =>
      {
          Thread.Sleep(3000);
          Console.WriteLine($"task ThreadId={Thread.CurrentThread.ManagedThreadId}");
          return "task over";
      });
    Console.WriteLine($"after await ThreadId={Thread.CurrentThread.ManagedThreadId}");
    return x;
}

通过var reslult = AsyncTest2().Result;调用即可。但注意如果调用Wait或Result的代码位于UI线程,Task的实际执行在其他线程,其需要返回UI线程则会造成死锁,所以应该Async all the way

2、优雅

从上面简单示例中可以看出异步编程的执行逻辑:主线程A逻辑->异步任务线程B逻辑->主线程C逻辑。

异步方法的返回类型只能是void、Task、Task。示例中异步方法的返回值类型是Task,通常void也不推荐使用,没有返回值直接用Task就是

上一篇也大概了解到如果我们要在任务中更新UI,需要调用Invoke通知UI线程来更新,代码看起来像下面这样,在一个任务后去更新UI

private void button1_Click(object sender, EventArgs e)
{
    var ResultTask = Task.Run(() => {
        Thread.Sleep(5000);
        return "任务完成";
    });
    ResultTask.ContinueWith((r)=> 
    {
        textBox1.Invoke(() => {
            textBox1.Text = r.Result;
        });
    });
}

如果使用async/await会看起来像这样,是不是优雅了许多。以看似同步编程的方式实现异步

private async void button1_Click(object sender, EventArgs e)
{
    var t = Task.Run(() => {
        Thread.Sleep(5000);
        return "任务完成";
    });
    textBox1.Text = await t;
}

3、最后

在.NET 4.5中引入的Async和Await两个新的关键字后,用户能以一种简洁直观的方式实现异步编程。甚至都不需要改变代码的逻辑结构,就能将原来的同步函数改造为异步函数。

在内部实现上,Async和Await这两个关键字由编译器转换为状态机,通过System.Threading.Tasks中的并行类实现代码的异步执行。

本文来自 C#.Net教程 栏目,欢迎学习!  

위 내용은 .NET의 비동기 비동기, 스레드 멀티스레딩의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
이 기사는 博客园에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제
C# .NET : 핵심 개념 탐색 및 프로그래밍 기초C# .NET : 핵심 개념 탐색 및 프로그래밍 기초Apr 10, 2025 am 09:32 AM

C#은 Microsoft가 개발 한 최신 객체 지향 프로그래밍 언어이며 .NET 프레임 워크의 일부로 개발되었습니다. 1.C#은 캡슐화, 상속 및 다형성을 포함한 객체 지향 프로그래밍 (OOP)을 지원합니다. 2. C#의 비동기 프로그래밍은 응용 프로그램 응답 성을 향상시키기 위해 비동기 및 키워드를 기다리는 키워드를 통해 구현됩니다. 3. LINQ를 사용하여 데이터 컬렉션을 간결하게 처리하십시오. 4. 일반적인 오류에는 NULL 참조 예외 및 인덱스 외 예외가 포함됩니다. 디버깅 기술에는 디버거 사용 및 예외 처리가 포함됩니다. 5. 성능 최적화에는 StringBuilder 사용 및 불필요한 포장 및 Unboxing을 피하는 것이 포함됩니다.

C# .NET 응용 프로그램 테스트 : 장치, 통합 및 엔드 투 엔드 테스트C# .NET 응용 프로그램 테스트 : 장치, 통합 및 엔드 투 엔드 테스트Apr 09, 2025 am 12:04 AM

C#.NET 애플리케이션에 대한 테스트 전략에는 단위 테스트, 통합 테스트 및 엔드 투 엔드 테스트가 포함됩니다. 1. 단위 테스트를 통해 MSTEST, NUNIT 또는 XUNIT 프레임 워크를 사용하여 코드의 최소 단위가 독립적으로 작동합니다. 2. 통합 테스트는 일반적으로 사용되는 시뮬레이션 된 데이터 및 외부 서비스를 결합한 여러 장치의 기능을 확인합니다. 3. 엔드 투 엔드 테스트는 사용자의 완전한 작동 프로세스를 시뮬레이션하며 셀레늄은 일반적으로 자동 테스트에 사용됩니다.

Advanced C# .NET 튜토리얼 : ACE 귀하의 다음 선임 개발자 인터뷰Advanced C# .NET 튜토리얼 : ACE 귀하의 다음 선임 개발자 인터뷰Apr 08, 2025 am 12:06 AM

C# 수석 개발자와의 인터뷰에는 비동기 프로그래밍, LINQ 및 .NET 프레임 워크의 내부 작업 원리와 같은 핵심 지식을 마스터하는 것이 필요합니다. 1. 비동기 프로그래밍은 비동기를 통해 작업을 단순화하고 응용 프로그램 응답 성을 향상시키기 위해 기다리고 있습니다. 2.linq는 SQL 스타일로 데이터를 운영하고 성능에주의를 기울입니다. 3. Net Framework의 CLR은 메모리를 관리하며 가비지 컬렉션은주의해서 사용해야합니다.

C# .NET 인터뷰 질문 및 답변 : 전문 지식 레벨 업C# .NET 인터뷰 질문 및 답변 : 전문 지식 레벨 업Apr 07, 2025 am 12:01 AM

C#.NET 인터뷰 질문 및 답변에는 기본 지식, 핵심 개념 및 고급 사용이 포함됩니다. 1) 기본 지식 : C#은 Microsoft가 개발 한 객체 지향 언어이며 주로 .NET 프레임 워크에 사용됩니다. 2) 핵심 개념 : 위임 및 이벤트는 동적 바인딩 방법을 허용하고 LINQ는 강력한 쿼리 기능을 제공합니다. 3) 고급 사용 : 비동기 프로그래밍은 응답 성을 향상시키고 표현 트리는 동적 코드 구성에 사용됩니다.

C# .NET을 사용하여 마이크로 서비스 구축 : 건축가를위한 실용 가이드C# .NET을 사용하여 마이크로 서비스 구축 : 건축가를위한 실용 가이드Apr 06, 2025 am 12:08 AM

C#.net은 강력한 생태계와 풍부한 지원으로 인해 마이크로 서비스를 구축하는 데 인기있는 선택입니다. 1) ASP.NETCORE를 사용하여 RESTFULAPI를 작성하여 주문 생성 및 쿼리를 처리하십시오. 2) GRPC를 사용하여 마이크로 서비스 간의 효율적인 통신을 달성하고 주문 서비스를 정의하고 구현하십시오. 3) Docker Containerized 마이크로 서비스를 통해 배포 및 관리를 단순화합니다.

C# .NET 보안 모범 사례 : 일반적인 취약점 방지C# .NET 보안 모범 사례 : 일반적인 취약점 방지Apr 05, 2025 am 12:01 AM

C# 및 .NET의 보안 모범 사례에는 입력 확인, 출력 인코딩, 예외 처리, 인증 및 인증이 포함됩니다. 1) 일반 표현식 또는 내장 방법을 사용하여 악성 데이터가 시스템에 들어가는 것을 방지하기 위해 입력을 확인하십시오. 2) XSS 공격을 방지하기 위해 출력 인코딩 httputility.htmlencode 메서드를 사용하십시오. 3) 예외 처리는 정보 유출을 피하고 오류를 기록하지만 자세한 정보를 사용자에게 반환하지는 않습니다. 4) ASP.NETIDENITY 및 CAMPLES 기반 승인을 사용하여 신청서를 무단 액세스로부터 보호합니다.

C 언어 : 무엇을 의미 하는가C 언어 : 무엇을 의미 하는가Apr 03, 2025 pm 07:24 PM

C 언어의 결장의 의미 ( ':') : 조건부 명세서 : 조건부 표현 및 명령문 분리 블록 루프 문 : 초기화, 조건부 및 증분 표현식 매크로 정의 분리 : 매크로 이름 및 매크로 값 단일 라인 주석 설명 : 콜론에서 라인으로의 내용을 주석 차원으로 표현

C 언어에서 무엇을 의미 하는가C 언어에서 무엇을 의미 하는가Apr 03, 2025 pm 07:21 PM

A In Canue in-Conecrease Operator이며 운영 메커니즘에는 다음이 포함됩니다. 먼저 변수 값을 얻습니다. a. A의 값을 1 x 1. 증가 후 A의 값을 반환합니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

안전한 시험 브라우저

안전한 시험 브라우저

안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

MinGW - Windows용 미니멀리스트 GNU

MinGW - Windows용 미니멀리스트 GNU

이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.

PhpStorm 맥 버전

PhpStorm 맥 버전

최신(2018.2.1) 전문 PHP 통합 개발 도구